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.
Related
I'm writing simple http server.
I want to shutdown socket after server send all data.
I considered that compare return byte of write() to socket with actuall content length, but I had read that the return value just means that data moved to send-buffer of the socket. (Im not sure and I don't know how can I check it)
If so, can I shutdown the socket just after check the bytes are same? What if the datas sended need to be retransmitted at TCP level after server send FIN flag?
The OS does not discard data you have written when you call shutdown(SHUT_WR). If the other end already shut down its end (you can tell because you received 0 bytes) then you should be able to close the socket, and the OS will keep it open until it has finished sending everything.
The FIN is treated like part of the data. It has to be retransmitted if the other end doesn't receive it, and it doesn't get processed until everything before it has been received. This is called "graceful shutdown" or "graceful close". This is unlike RST, which signals that the connection should be aborted immediately.
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.
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))
I am trying to use the sockets package for Octave on my Ubuntu. I am using the Java Sockets API for connecting to Octave. The Java program is the client, Octave is my server. I just tried your code example:
http://pauldreik.blogspot.de/2009/04/octave-sockets-example.html
There are two problems:
1.)
Using SOCK_STREAM, for some strange reason, certain bytes are being received by recv() right after accept(), even if I'm not sending anything from the client. Subsequent messages I send with Java have no effect, it seems the Octave socket completely has its own idea about what it thinks it receives, regardless of what I'm actually sending.
2.)
Using SOCK_DGRAM, there is another problem:
I do get a reception of my actual message this way, but it seems that a recv() command doesn't remove the first element from the datagram queue. Until I send the second datagram to the socket, any subsequent recv() commands will repeatedly read the first datagram as if it were still in the queue. So the recv() function doesn't even block to wait for an actually new available datagram. Instead, it simply reads the same old one again. This is useless, since I cannot tell my server to wait for news from the client.
Is this how UDP is supposed to behave? I thought datagram packets are really removed from the datagram queue by recv().
This is my server side code:
s=socket(AF_INET, SOCK_DGRAM, 0);
bind(s,12345);
[config,count] = recv(s, 10)
[test,count] = recv(s, 4)
And this is my Java client:
public LiveSeparationClient(String host, int port, byte channels, byte sampleSize, int sampleRate, int millisecondsPerFrame) throws UnknownHostException, IOException {
this.port = port;
socket = new DatagramSocket();
this.host = InetAddress.getByName(host);
DatagramPacket packet = new DatagramPacket(ByteBuffer.allocate(10)
.put(new byte[]{channels, sampleSize})
.putInt(sampleRate)
.putInt(millisecondsPerFrame)
.array(), 10, this.host, port
);
socket.send(packet);
samplesPerFrame = (int) Math.floor((double)millisecondsPerFrame / 1000.0 * (double)sampleRate);
}
As you see, I'm sending 10 Bytes and receiving all 10 (this works so far) with recv(s, 10). In the later part of my Java program, packets will be generated and send also, but this may take some seconds. In the mean time, the second receive, recv(s, 4), in Octave should wait for a really new datagram package. But this doesn't happen, is simply reads the first 4 Bytes of the same old package again. recv() doesn't block the second time.
I hope it is not a problem for you to fix this?
Thanks in advance :-)
Marvin
P.S.: Also, I don't undertstand why listen() and accept() are both necessary when using SOCK_STREAM, but not for SOCK_DGRAM.
Usually Python chat servers contain the following lines :
while 1:
data = conn.recv(1024)
if not data: break
where the connection conn was defined as :
conn, addr = s.accept()
It seems to me that when the connection is closing, the client sends an empty string to the server. Am I right ?
Yes, this is correct.
And now this answer is not too short anymore.
On a blocking socket, recv() blocks until it can return at least one byte of data. If the other end closes the socket, recv() returns an empty string (zero bytes of data).