I have set a timeout on my blocking socket ..
DWORD to = 1200;
if (setsockopt (soc, SOL_SOCKET, SO_RCVTIMEO, (char *)&to, sizeof(to))) {
...
}
In the case that recv () then returns zero, how can I tell this is link disconnected or read timed out? If it's t/o I would like to read more, if it's discon I would like to take other action. I realise I could just remove the t/o, then I would know it's discon, but I also need to routinely monitor how the read process is progressing.
Any help much appreciated. Cheers - Rich
From the SO_RCVTIMEO section of the man page for socket:
...if no data has been transferred and the time‐out has been reached,
then -1 is returned with errno set to EAGAIN or EWOULDBLOCK, or
EINPROGRESS (for connect(2)) just as if the socket was specified to
be non‐blocking.
From the man page for recv:
These calls return the number of bytes received, or -1 if an error
occurred. In the event of an error, errno is set to indicate the
error.
When a stream socket peer has performed an orderly shutdown, the
return value will be 0 (the traditional "end-of-file" return).
Datagram sockets in various domains (e.g., the UNIX and Internet
domains) permit zero-length datagrams. When such a datagram is
received, the return value is 0.
The value 0 may also be returned if the requested number of bytes to
receive from a stream socket was 0.
A call to recv will return 0 on disconnect, or if a zero-length datagram is received, or if the requested number of bytes is 0.
A call to recv will return -1 on any error, including a timeout. You need to examine errno to differentiate between a timeout versus some other error.
Related
What happens if signal interrupts sendto or recvfrom call on datagram socket? Can I expect that these calls always return -1 with errno == EINTR or they can return positive number of bytes, but I shall repeat the call entirely?
On a datagram socket, sendto and recvfrom always send and receive complete datagrams, or nothing at all. If they could stop in the middle of a datagram that would defeat the point of datagrams.
There is an exception - recvfrom might cut off the end of a datagram if the buffer is too small. The entire datagram is received, but your program doesn't get to see all of it.
I am implementing a UNIX domain socket Inter Process communication code and I hit this error randomly - "errno 11: Resource temporarily unavailable" while trying to read from the socket. I use MSG_PEEK to read the number of bytes from the socket, and allocate bytes for receive buffer, and read the actual data.
The socket is a blocking socket and I do not have any code to have non-blocking (in all, accept/read/write). Any pointers on what could cause this on a blocking socket read? From the man page of MSG_PEEK, it seems like EAGAIN could be returned when socket is marked as non-blocking, using O_NONBLOCK.
The failure happens on the recv call below.
char temp_buffer[BUFFER_MAX];
num_bytes = recv(_connection_fd, &temp_buffer, BUFFER_SIZE_MAX, MSG_PEEK | MSG_TRUNC);
if (num_bytes < 0) {
LogError("Error reading from socket. %s", strerror(errno));
close(_connection_fd);
return -1;
}
.....
<Allocate memory>
.....
// Read actual data
num_bytes = read(_connection_fd, buffer, num_bytes);
...
<Send response back to client>
<Close socket descriptor>
It may also happen to blocking socket and blocking recv, if socket has timeout SO_RCVTIMEO option set (default is 0). BTW, did you consider select() before recv()?
An existing program is written this way for UDP socket (in blocking mode):
while (true) {
poll();
if (POLLIN is set) {
read(fd, buf, bufSize);
}
}
For UDP, each read() read 1 and only 1 datagram (packet). If there are multiple packets available in the socket recv buf, the above code reads 1 packet only at each read(). My question is: will the next poll() return immediately, thus the above code still can read from socket very quickly? Or could next poll() wait until there is new packet arrives on the socket thus the code effectively falls behind in reading?
The doc seem to suggest that next poll() will return immediately as long as there are data in the buffer. But the code seem to fall behind in reading, and I don't know the cause is in the above code or somewhere else.
The preferred way is likely:
set the socket to non blocking
read in the loop until errno = EWOULDBLOCK or EAGAIN
Thanks.
If there is already data in the socket buffer when poll() is called, it should signal POLLIN immediately if POLLIN is requested, yes. It should not wait for the next packet to arrive in the buffer before signaling POLLIN.
If the server sends 4 bytes
send(sock, buffer1, 4, 0);
And client waits for exactly 4 bytes
recv(sock, buffer2, 4, 0);
Is there a possibility that less than 4 bytes will be written to buffer2?
No other send or recv was made before.
If there is no possibility, what's the maximum size of buffer that send can do, so that recv could get the same buffer size in one call.
There's no such thing as a "message", except what you delimit yourself.
REPEAT: THERE IS NO SUCH THING AS A MESSAGE.
TCP does not send messages, it sends an octet stream.
You need to send in a loop, in case there is a backlog of unacknowledged data and send does not use the whole buffer you passed in. You need to recv in a loop, in case the sending stack chunked it in an unexpected way. You need to delimit your messages (eg by prepending a network-endian length), so you can recover them properly.
From the man page for recv:
"These calls return the number of bytes received, or -1 if an error occurred.
For TCP sockets, the return value 0 means the peer has closed its half side of the connection."
As such recv is always allowed return all of the bytes sent, fewer than the bytes sent, or none of the bytes sent. You cannot assume anything simply because you happen to know what send is doing at the other end of the connection.
There is no way to guarantee that you can always get complete message.
Yes, there's this possibility. In fact, recv gives you as return value the amount of bytes received.
I have a very annoying problem that I found several times on other forums but I can't find a proper solution.
The problem is recv() returns 0 on the last few bytes of a connection. Here are some background information.
Both (client / server) applications run on the same machine.
Both (client / server) sockets are non-blocking
The transfered data size is 53 bytes.
Both (client / server) call shutdown and closesocket when the last send()/recv() was executed.
I also tried with SO_LINGER and 10 seconds, no success either
I call send() several times (small chunks) and from the client side 53 bytes are transfered.
The server calls recv() several times (4 byte requests) and read 49 bytes and then returns 0 (54 Bytes - 49 Bytes, so 4 bytes are missing).
MSDN and some forums write for non-blocking sockets:
recv() definitely returns < 0 on error and errno / WSAGetLastError is set
recv() definitely returns = 0 when the other side closed the connection
recv() definitely returns > 0 when data was read
MSDN also says:
Using the closesocket or shutdown functions with SD_SEND or SD_BOTH
results in a RELEASE signal being sent out on the control channel. Due
to ATM's use of separate signal and data channels, it is possible that
a RELEASE signal could reach the remote end before the last of the
data reaches its destination, resulting in a loss of that data. One
possible solutions is programming a sufficient delay between the last
data sent and the closesocket or shutdown function calls for an ATM
socket.
This is regarded in the example of recv() and send(): http://msdn.microsoft.com/en-us/library/windows/desktop/ms740121(v=vs.85).aspx
But still no success, I still get some interrupts in 10% of all connections after the 49 Byte is received, 90% of the connections succeed. Any ideas? Thx.
recv() returns 0 only when you request a 0-byte buffer or the other peer has gracefully disconnected. If you are not receiving all of the data you are expecting, then you are not reading the data correctly to begin with. Please update your question with your actual code.
My guess is that you're not really sending all the data you think your are sending. Check out:
The Ultimate SO_LINGER page
recv() definitely returns = 0 when the other side closed the connection
This is not completely true, in the following code using non-blocking winsock2 tcp, when no data is available, select returns 1 and recv returns 0, as does WSAGetLastError().
fd_set test = {1, socket};
const timeval timeout = {0, 0};
if (!::select(0, &test, nullptr, nullptr, &timeout)) return 0;
int done = ::recv(socket, buffer, 1, 0);
This continues even after the other end has called:
::shutdown(socket, SD_BOTH);
::closesocket(socket);
and then ended. Communication works as expected, it is just ::recv that seems to be "broken".