Python / tcp / ascii / How to be able to send an ascii command to a server while continuously receiving incoming ascii string from the server? - server

I'm working on a project related with some naval radar and how to use the data that its internal "server" sends while rotating about other ships.
the documentation for the radar protocol: here
The main idea is to create a client application to receive the data sent from the radar server, which are ascii sentences containing other ship's information, like speed, position, etc. those are always being sent on a tcp connection.
at the same time, the client must be able to send command in the same format, something like:
<command>[,<argument#1>][,<argument#2>][,...][,<argument#n>]<eol>
to ask for a specific ship information for example.
so all I have until now is this basic client (please dismiss the nonsense #coments on it)
import socket
import time
#try:
#ip = raw_input('IP: ')
#except:
#ip = input('IP: ')
#puerto = input("PUERTO??")
#MESSAGE=b'#000\r'
ip = '127.0.0.1'
puerto = 1235
try:
srvsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print('Failed to create socket')
sys.exit()
print('Socket Created')
srvsock.connect((ip, puerto))
srvsock.setblocking(0)
print ('Conectado a ' + ip + ':' + str(puerto))
while True:
#listening and receiving ascii strings (buf) from radar
try:
buf = srvsock.recv(1024)
if buf == 'stop':
break
elif len(buf) > 0:
print(buf)
except:
print('error de cliente')
break
# how to be able to send commands while listening the radar??
#try:
#msg = raw_input ('Mensage: ')
#msgencode = msg.encode ('ascii')
#srvsock.send(msgencode)
#except socket.error:
#print('Failed to send data')
#break
srvsock.close()
So the idea is to be listening all the time the incoming ascii strings sent by the server... and also being able to send commands from the client app to the sever to request more data.
I'm still working on this but any better or professional way of doing this would be really appreciated. I'm a little bit confuse with the implementation of a non blocking code to do this.

Related

TCP Socket between Ada and Python

I'm really new to Ada and would like to create a TCP socket between Ada and Python. The Ada programm should act as server and the Python program as client. The main use case is to receive string commands from Python and confirm their execution.
Without the Ada.Streams.Write(Channel.All, Data); in the Ada Server and the data = s.recv(512) it is at least possible to receive a Hello World from the Python Client.
I would like to send an answer from the Ada server to the Python client, that's the point where I stuck. I get an "Socket Error Connection Timed Out".
Ada Server:
use GNAT.Sockets;
Server : Socket_Type;
Socket : Socket_Type;
Address : Sock_Addr_Type;
Channel : Stream_Access;
Data : Stream_Element_Array(1 .. 512);
Last : Stream_Element_Offset;
S : Unbounded_String;
begin
Put_Line("Server Config Started..");
Create_Socket(Server);
Set_Socket_Option(Server,
Socket_Level,
(Reuse_Address, True));
Set_Socket_Option(Server, Socket_Level,(Receive_Timeout, Timeout => 5.0));
Bind_Socket(Server, Address => (Family => Family_Inet, Addr => Inet_Addr("127.0.0.2"), Port => 65432));
Listen_Socket(Server);
Accept_Socket(Server, Socket, Address);
Put_Line("Client connected from:" & Image(Address));
Channel := Stream(Socket);
Ada.Streams.Read(Channel.All, Data, Last);
Put_Line("Received:");
for I in 1 .. Last loop
Put(Character'Val(Data(I)));
end loop;
Ada.Streams.Write(Channel.All, Data);
Python Client:
HOST = '127.0.0.2'
PORT = 65432
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b'Hello, world')
data = s.recv(512)
What am I doing wrong? Has someone a hint?
Thanks in advance.
The reason things don’t go the way you hoped is that you’ve put the Receive_Timeout socket option on the Server socket; you need to put it on Socket instead, since that’s the socket you’re receiving from.
As things stand: the call
Ada.Streams.Read(Channel.All, Data, Last);
will terminate either when it has read Data’Length (512) bytes or when the other end closes the socket.
Before you included the data = s.recv(512) at the end of the Python script, the Python was closing the socket.
Now, it’s waiting for the Ada side to send it 512 bytes back - and the Ada side is waiting for the Python side to send it the remaining (512 - 12) bytes. Classic deadly embrace.
How to fix? possibly, have the Ada side read character-by-character until it reads a terminator (e.g. \0). Or you could use datagrams. In any case, you need a protocol to determine message boundaries on the wire.
On macOS, the Ada side prints out the message it has received as soon as the Python side sends it. This is not what the man page for setsockopt() says re: SO_RCVTIMEO! It should wait for the timeout set (5 seconds) before deciding to give up.

Send and read data through socket from fiber

Trying to figure out how to send/read data through socket. On remote server I create new netcat -l 4444 and from local send text data echo "test" | netcat remote.host 4444. This is always works fine.
Trying to reproduce:
require "socket"
HOST = "remote.host"
PORT = 4444
ch_request = Channel(String).new
ch_response = Channel(String).new
spawn do
socket = TCPSocket.new(HOST, PORT)
loop do
select
when request = ch_request.receive
socket << request
socket.flush
end
if response = socket.gets
ch_response.send response
end
end
end
sleep 0.1
ch_request.send "hello"
loop do
select
when response = ch_response.receive
pp response
end
end
In my dream I send data to channel, read it from first loop then send to socket. The same way but reverse order need for read it from second loop.
On practice this is not happens. On local after connect I got "test" and can't send back anything. On remote I can send to local but on local got only empty string once and nothing more after.
What mean this behavior and how to achieve planned?
You didn't show this, but I suppose you have a second implementation using TCPServer for the netcat -l equivalent.
You need to use separate fibers for reading/writing to the socket and the channel. It's a bit hard to judge what exactly happens without seeing the server, but I suppose you end up in a deadlock where both sides are waiting on input of the other side or user, but cannot proceed to actually send or read anything. In other words you interlocked the sending/receiving part, requiring the other side to carefully react and interplay so to not lock up the client. This is obviously a brittle approach.
Instead you should make sure any fiber does not do more than one operation in a loop. One receives from the socket and forwards that to a channel, the second one receives from a channel and forwards that to the socket, the third one receives from the reader side channel and prints or does whatever you want to do the data and the last one fills the sender channel. This way no operation can block one of the others. Of course one of those fibers should simply be the main program one.
In the server you additionally need one fiber that accepts the client connections and spawns the sender and receiver loops for each.
Finally note that a select statement with a single when branch has no effect, you can make the call directly. select is useful if you need to read or write to multiple channels concurrently in the same fiber, so for example if you would have multiple channels providing data to be send out to a socket, you would use select to not have the messages be corrupted by two fibers writing to the same socket at the same time. An additional usecase for select is to send or receive from a channel with a timeout.
Who is looking for an answer to similar questions. The final result what I wanted looks like this:
# Open socket for simulate remote server: `netcat -v -4 -l 4444`
require "socket"
HOST = "remote.host"
PORT = 4444
# JFYI: In real life this packed into class and I use class variable instead consts.
TUBE_REQUEST = Channel(String).new
TUBE_RESPONSE = Channel(String).new
SOCKET = TCPSocket.new(HOST, PORT)
spawn do
until SOCKET.closed?
if request = TUBE_REQUEST.receive
SOCKET << request
SOCKET.flush
end
end
end
spawn do
until SOCKET.closed?
if response = SOCKET.gets
TUBE_RESPONSE.send response
end
end
end
sleep 0.1
def receive_response
TUBE_RESPONSE.receive
end
def send(message, wait_for_response = true)
TUBE_REQUEST.send message
receive_response if wait_for_response
end
send("command with response")
send("command with new line and response\n")
send("command without new line and response", false)
It will send each command and wait for answer (except the last) from remote and then call the next command.

How does socket recv function detects end of message

Look at this small basic python programs:
import socket
tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpsock.bind(("", 10000))
tcpsock.listen(10)
(sock, (ip, port)) = tcpsock.accept()
s = sock.recv(1024)
print(s)
Second program:
import socket
import time
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', 10000))
time.sleep(1)
sock.sendall(b'hello world')
The first program is a socket server. It recv a message through the socket and display it on the console. The second program is a client which connects to the server and sends it a message.
As you can see, the server reads a 1024 bytes max length message. My client send a few bytes.
My question is: How does the server knows the message ends after the 'd' char ?
I am working with sockets since years and i have always implemented a delimiter mechanism in order to know when the message stops.
But it seems to work automaticly. My question is: How ?
I know TCP car fragment messages. So what's happen if the paquet is trucated in the middle of my message ? Is it managed by OS ?
Thanks
How does the server knows the message ends after the 'd' char ?
It does not. There is not even a concept of a message in TCP. recv simply returns what is there: it blocks if no data are available and returns what can be read up to the given size if data are available. "Data available" means that there are data in the sockets receive buffer, which are put by the OS kernel there. In other words: recv will not block until the requested number of bytes can be returned but it will already return when at least a single byte is in the sockets receive buffer.
For example if the client would do two send or sendall shortly after each other a single recv might return both "messages" together. This can be easily triggered by deferring the recv (add some sleep before it) so that both "messages" are guaranteed to be arrived at the client.

Connected Unix SOCK_DGRAM sockets

I've followed the code in this answer to create a pair of programs which send and receive datagrams via a Unix socket.
What's awkward about this: On the side which creates the first socket (i.e. the "server"), I can't use calls to send, recv, read or write because there is no destination set (those calls fail with "Destination address required" error.
I've tried working around this by adding an initial call to recvfrom and using the address given back through there, but it never has the correct value (on OSX at least). It also doesn't work to use sendto since we don't know the client address.
The way which I have got it working is roughly following this process:
Start server program, which:
Calls socket and bind to create the server socket.
It waits here.
Start client program, which:
Calls socket and bind to create the client socket.
It knows the path to the server socket and calls connect.
This side is now set up correctly.
Server program:
Accepts the path to the client socket via stdin
Copies the path to a struct sockaddr_un and uses that to call connect (as in the linked answer).
This is pretty awkward! If I was doing this with SOCK_STREAM sockets, I could use listen and accept; the flow is much more straight-forward without the server needing to know the client's socket path.
Is there a more elegant way of getting these sockets connected?
SOCK_DGRAM (UDP) sockets are "Connectionless", so you cannot "connect" the two sockets. They only send packets to the designated destination address and the client simply captures it. So you'll to first decide if you are going to use a SOCK_DGRAM (UDP) or SOCK_STREAM (TCP).
If you are using UDP sockets the client side socket need not connect, you simply sendto the destination address (Server in this case) after creating and binding.
So if you need a dedicated connected connection you are better off using TCP socket. Or if you are using this over the internet the closest thing you can find for UDP is Hole punching.
One way to solve the problem:
Your messages probably have common header.
Add address information of sender to the header.
Then your server can respond to the correct client by using sendto.
Pseudo example:
void handle_my_message(const my_message_t *msg)
{
struct sockaddr_un client_address = msg->header.sender;
my_message_response_t response_msg;
... handle the message and fill the response...
// Send response message
sendto(fd, &response_msg, sizeof(response_msg), 0,
(struct sockaddr*)&client_address, sizeof(client_address));
}
This way your server programs does not need to keep book of connections.
Instead of struct sockaddr_un in the header you maybe should use something smaller and more portable format, that can be converted to struct sockaddr_un.
You should also bind the client side socket to an address. If the client socket is bound (i.e. has its own name), then you don't need an out-of-band mechanism to communicate the client's address to the server. The OS sends it along with each datagram.
Sample code for client (in python because it's quick and easy to prototype -- should be easy to translate to the equivalent C):
#!/usr/bin/env python3
import os
import socket
server_addr = "/tmp/ux_server"
client_addr = "/tmp/ux_client"
if os.path.exists(client_addr):
os.remove(client_addr)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(client_addr)
for n in range(5):
data = "Hello " + str(n)
data = data.encode()
print("Sent '{}' to {}".format(data, server_addr))
sock.sendto(data, server_addr)
data, addr = sock.recvfrom(16000)
print("Got '{}' back from {}".format(data, addr))
Furthermore, you can execute a connect on the client side. Since it's a datagram socket, that doesn't actually create a connection between the two but it does fix the address of the server endpoint, relieving you of the need to provide the server address on every send (i.e. you can use simple send rather than sendto).
For completeness, here's the echo server corresponding to the above:
#!/usr/bin/env python3
import os
import socket
server_addr = "/tmp/ux_server"
if os.path.exists(server_addr):
# Bind will fail if endpoint exists
os.remove(server_addr)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(server_addr)
while True:
data, addr = sock.recvfrom(16000)
print("Got '{}' from {}".format(data, addr))
sock.sendto(data, addr)
EDIT
Hmm... I see now that you say you're already binding the client socket, and then connecting to the server side. But that means you simply need to have the server use recvfrom once initially to obtain the client's address. The OS will send the address along and you don't need to use an out-of-band mechanism.
The downside to connecting the socket is that if the client goes down, the server won't know that unless it attempts to send, but the client won't be able to reconnect because the server's socket is already connected. That's why datagram servers typically use recvfrom and sendto for all messages.
Updated server with initial recvfrom followed by connect:
#!/usr/bin/env python3
import os
import socket
server_addr = "/tmp/ux_server"
if os.path.exists(server_addr):
# Bind will fail if endpoint exists
os.remove(server_addr)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(server_addr)
client_addr = None
while True:
if client_addr:
data = sock.recv(16000)
else:
data, client_addr = sock.recvfrom(16000)
sock.connect(client_addr)
print("Got '{}' from {}".format(data, client_addr))
sock.send(data)
Updated client with connected socket.
#!/usr/bin/env python3
import os
import socket
server_addr = "/tmp/ux_server"
client_addr = "/tmp/ux_client"
if os.path.exists(client_addr):
os.remove(client_addr)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(client_addr)
sock.connect(server_addr)
for n in range(5):
data = ("Hello " + str(n)).encode()
print("Sent '{}'".format(data))
sock.send(data)
data = sock.recv(16000)
print("Got '{}' back".format(data))

Python APNs does not process request

I'm trying to implement a server side script for sending push notifications to apple push notification server. I create the ssl connection, I send the payload - but am unable to get a response from the APNs. Here is my code:
import socket, ssl, pprint, struct, time, binascii
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# require a certificate from the server
ssl_sock = ssl.wrap_socket( s,
keyfile="/Users/Jeff/Desktop/pickmeup-key2-noenc.pem",
certfile="/Users/Jeff/Desktop/pickmeup-cert2.pem",
server_side=False,
do_handshake_on_connect=True,
cert_reqs=ssl.CERT_REQUIRED,
ca_certs="/Users/Jeff/Desktop/entrustrootcert.pem",)
#ciphers="ALL")
ssl_sock.connect(('gateway.sandbox.push.apple.com', 2195))
print repr(ssl_sock.getpeername())
print ssl_sock.cipher()
print pprint.pformat(ssl_sock.getpeercert())
command = '\x00'
identifier = 1987
expiry = time.time()
deviceToken = "9858d81caa236a86cc67d01e1a07ba1df0982178dd7c95aae115d033b93cb3f5"
alert = "This is a test message"
sound = "UILocalNotificationDefaultSoundName"
payload = "{\"aps\":{\"alert\":\"%s\",\"sound\":\"%s\"}}" %(alert, sound)
packetFormat = "!cIIH%dsH%ds" %(32, len(payload))
packet = struct.pack(packetFormat,
command,
identifier,
int(expiry),
32,
binascii.unhexlify(deviceToken),
len(payload),
payload)
nBytesWritten = ssl_sock.write(packet)
print "nBytesWritten = %d" %(nBytesWritten)
data = ssl_sock.read(1024)
print len(data)
ssl_sock.close()
Running this script, I generate the following output:
('17.149.34.132', 2195)
('AES256-SHA', 'TLSv1/SSLv3', 256)
{'notAfter': 'May 31 00:04:27 2012 GMT',
'subject': ((('countryName', u'US'),),
(('stateOrProvinceName', u'California'),),
(('localityName', u'Cupertino'),),
(('organizationName', u'Apple Inc'),),
(('organizationalUnitName', u'Internet Services'),),
(('commonName', u'gateway.sandbox.push.apple.com'),))}
nBytesWritten = 133
0
Any ideas on what might be going wrong? (I am sending enhanced push notifications so I am expecting a response from apple push notification server)
The key thing to note is that read() is returning no data. In Python, read() is supposed to block until data is available or the connection closes. Apple is closing your connection.
Why? Well, probably because you sent a malformed request. command=0 is a normal push notification; command=1 is enhanced. The big-endian 1987 will be interpreted as a 0-byte device token and a 1987-byte payload, neither of which are valid.
(And FWIW, I'd use B instead of c for the command ID; it seems to make more sense.)
you may consider https://github.com/djacobs/PyAPNs that wrapped lot of useful features, including:
error handling
support enhanced message format and auto resend messages which are sent before error response
non-blocking ssl socket connection with great performance
Apple Push notification server doesn't give a response, it's a one-way binary socket.
Rather than rolling your own solution you could try apns-python-wrapper or apns