I use nonblocking UNIX UDP socket to transfer data from one process to another:
audio_s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
audio_s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 5500000)
audio_s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 5500000)
audio_s.setblocking(0)
try:
os.remove(SOCKET_PATH)
except FileNotFoundError as e:
pass
audio_s.bind(SOCKET_PATH)
And I often send data to remote process:
audio_s.sendto(data, REMOTE_SOCKET_PATH)
But sometimes (very rare) I catch BlockingIOError: [Errno 11] Resource temporarily unavailable on sendto call. What reason can be for this? Resource temporarily unavailable looks like very generic sentence.
Is it possible to know more detailed information? For example send buffer overflowed of remote receive buffer overflow? Are these possible reasones? or only 1 of them?
Can I control current datagram count in send/receive buffer?
What is correct way to process or avoid this situation?
If I remove line with:
audio_s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 5500000)
it works without this exception
Errno 11 is EAGAIN, from 'man sendto':
[EAGAIN] The socket is marked non-blocking and the requested operation would block.
Good explanations are there:
When a non-blocking send() only transfers partial data, can we assume it would return EWOULDBLOCK the next call?
and there:
EAGAIN Error: Using Berkeley Socket API
Related
I'm maintaining an embedded system that uses LwIP. The relevant code is as follows (edited):
iobSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connectRC = connect(socket, &serverAddress, sizeof(struct sockaddr));
FD_SET(socket, &fdset);
selectRC = select((socket) + 1, NULL, &fdset, NULL, &tv);
sendRC = send(iobSocket, dout, strlen(dout), 0);
This seems to work. When I remove the select() call, however, I get an error on the send() which sets errno to 119 or Connection already in progress. This error code isn't documented in the send() man pages.
Can someone tell me why the select() command is even necessary here, and why I might be getting an undocumented error without it?
Thank you.
Error code 119 is EINPROGRESS. It means the socket is operating in non-blocking mode 1, and the previous connect() operation hasn't finished yet, which is why the send() fails.
1: Which means, there must be more code that you are not showing, as sockets are normally in blocking mode when they are initially created, and require explicit code to put them into non-blocking mode, such as via fcntl(F_SETFL, O_NONBLOCK);.
Using select() to test the socket for writability allows your code to wait until the socket is actually done connecting and is ready for sending.
This is explained in the man page for connect():
RETURN VALUE
If the connection or binding succeeds, zero is returned. On error, -1 is returned, and errno is set to indicate the error.
ERRORS
The following are general socket errors only. There may be other domain-specific error codes.
...
EINPROGRESS
The socket is nonblocking and the connection cannot be completed immediately. (UNIX domain sockets failed with EAGAIN instead.) It is possible to select(2) or poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).
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.
I'm trying to create a server that sets up a Unix socket and listens for clients which send/receive data. I've made a small repository to recreate the problem.
The server runs and it can receive data from the clients that connect, but I can't get the server response to be read from the client without an error on the server.
I have commented out the offending code on the client and server. Uncomment both to recreate the problem.
When the code to respond to the client is uncommented, I get this error on the server:
thread '' panicked at 'called Result::unwrap() on an Err value: Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }', src/main.rs:77:42
MRE Link
Your code calls set_read_timeout to set the timeout on the socket. Its documentation states that on Unix it results in a WouldBlock error in case of timeout, which is precisely what happens to you.
As to why your client times out, the likely reason is that the server calls stream.read_to_string(&mut response), which reads the stream until end-of-file. On the other hand, your client calls write_all() followed by flush(), and (after uncommenting the offending code) attempts to read the response. But the attempt to read the response means that the stream is not closed, so the server will wait for EOF, and you have a deadlock on your hands. Note that none of this is specific to Rust; you would have the exact same issue in C++ or Python.
To fix the issue, you need to use a protocol in your communication. A very simple protocol could consist of first sending the message size (in a fixed format, perhaps 4 bytes in length) and only then the actual message. The code that reads from the stream would do the same: first read the message size and then the message itself. Even better than inventing your own protocol would be to use an existing one, e.g. to exchange messages using serde.
For c send function(blocking way) it's specified what function returns with size of sent bytes when it's received on destinations. I'm not sure that I understand all nuances, also after writing "demo" app with WSAIoctl and WSARecv on server side.
When send returns with less bytes number than asked in buffer-length parameter?
What is considered as "received on destinations"? My first guess it's when it sit on server's OS buffer and server application is notified. My second one it's when server application recv call have read it fully?
Unless you are using a (somewhat exotic) library, a send on a socket will return the number of bytes passed to the TCP buffer successfully, not the number of bytes received by the peer (see Microsoft´s docs for example).
When you are streaming data via a socket, you need to check the bytes effectively accepted into the TCP send buffer. That´s why usually a send command is inside a loop that will issue several sends if needed.
Errors in send are local: for example if the socket is closed by the peer during a sending operation (making your socket invalid) or if the operation times out (TCP buffer not emptying, i. e. peer not receiving data fast enough or some other trouble).
After all send is completed you have no easy way of knowing if the peer received all the bytes you sent. You´ll usually just issue closesocket and make sure that your socket has a proper linger option set (i. e. only close after timeout or sucessfully finishing the send). Alternatively you wait for a confirmation by the peer (for example via a recv that returns zero bytes, indicating that the connection was gracefully closed).
Edit: typo
I create epoll and register some non-blocking sockets which try connect to closed ports on localhost. Why epoll tells me, that i can write to this socket (it give event for one of created socket with eventmask contain EPOLLOUT)? But this socket doesn't open and if i try send something to it i get an error Connection refused.
Another question - what does mean even EPOLLHUP? I thought that this is event for refused connection. But how in this case event can have simultaneously EPOLLHUP and EPOLLOUT events?
Sample code on Python:
import socket
import select
poll = select.epoll()
fd_to_sock = {}
for i in range(1, 3):
s = socket.socket()
s.setblocking(0)
s.connect_ex(('localhost', i))
poll.register(s, select.EPOLLOUT)
fd_to_sock[s.fileno()] = s
print(poll.poll(0.1))
# prints '[(4, 28), (5, 28)]'
All that poll guarantees is that your application won't block after calling corresponding function. So you are getting what you've paid for - you can now rest assured writing to this socket won't block - and it didn't block, did it?
Poll never guarantees that corresponding operation will succeed.
poll/select/epoll return when the file descriptor is "ready" but that just means that the operation will not block (not that you will necessarily be able to write to it successfully).
Likewise for EPOLLIN: for example, it will return ready when a socket is closed; in that case, you won't actually be able to read data from it.
EPOLLHUP means that there was a "hang up" on the connection. That would really only occur once you actually had a connection. Also, the documentation (http://linux.die.net/man/2/epoll_ctl) says that you don't need to include it anyway:
EPOLLHUP
Hang up happened on the associated file descriptor. epoll_wait(2) will always wait for this event; it is not necessary to set it in events.