Confused about recv() - c

Pardon if this question has been answered but I couldn't find it.
I'm kinda confused about recv() and recvfrom(). Once the server binds the address (or accepts connection for TCP), recv() is called. Does recv() constantly check for messages that has been sent or does it wait until a message is received? If it does wait, how long is the wait time?
Not sure if I'm making sense, but if someone could enlighten me, I'd be grateful.

If no messages are available at the socket and O_NONBLOCK is not set on the socket's file descriptor, recv() shall block until a message arrives.
If no messages are available at the socket and O_NONBLOCK is set on the socket's file descriptor, recv() shall fail and set errno to [EAGAIN] or [EWOULDBLOCK].
Source: http://www.opengroup.org/onlinepubs/009695399/functions/recv.html

Note that you can implement a timeout using select() or poll(), which also lets you wait on multiple sockets at once.

Related

C socket send() dose not send all data before Main function returned

Here is the succinct code:
int main(){
/* here ellipsis socket connect malloc etc. */
send(socket,buffer, 1024*1024*1024,0);
return 1;
}
Question: If send() is blocked, no matter how large the buffer is, I think it will send all data before the main function returned. But actually, if the data large enough, the other socket end only receive a part of data which the send() function send. However, if I add this code before 'return 1;'
while(1){}
the other socket end receive intact data.
Does the send() is non_blocked?
or something wrong with send() function?
thanks advance.
When blocking socket is used, send() function blocks until last data is delivered to queue of local TCP-stack.
So send() may return when part of the data is still queued in local TCP-stack.
Because your process exits right after send() call, there can be undelivered data in local TCP stack during exit.
TCP stack may continue the data transfer after exit, if linger is enabled. Or TCP stack may reset the connection without any attempt to transfer undelivered data to the peer, if linger is disabled.
If you close the TCP connection gracefully when linger is enabled, then TCP-stack should (try to) deliver queued data to the peer.
Close the connection gracefully by adding close() call.
And make sure that SO_LINGER is enabled with reasonable timeout:
send(socket,buffer, 1024*1024*1024,0);
const struct linger linger_val = { 1, 600 };
setsockopt(socket, SOL_SOCKET, SO_LINGER, &linger_val, sizeof(linger_val));
close(socket);
return 1;
Usually there is no need to change SO_LINGER. More information about SO_LINGER in man page of socket(7):
SO_LINGER
When enabled, a close(2) or shutdown(2) will not return until
all queued messages for the socket have been successfully sent
or the linger timeout has been reached. Otherwise, the call
returns immediately and the closing is done in the background.
When the socket is closed as part of exit(2), it always
lingers in the background.
Whit 0 as flag, send() is like write() function:
https://linux.die.net/man/2/send
https://linux.die.net/man/2/write
and for write():
The number of bytes written may be less than count if, for example, there is insufficient space on the underlying physical medium, or the RLIMIT_FSIZE resource limit is encountered (see setrlimit(2)), or the call was interrupted by a signal handler after having written less than count bytes. (See also pipe(7).).
Check also this answer:
Blocking sockets: when, exactly, does "send()" return?
Hope this help
send() is blocking call, but it is blocked till all the data is pushed to sendbuffer. You can modify the program to exit when all the data is send from the socket. This is possible by reducing the sendbuffer size. you can use setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)send_buffer, send_buffer_sizeof);

How can timeout be implemented given the blocking nature of recvfrom and sendto?

I am trying to achieve the TIMEOUT functionality in my UDP Stop-and-wait. That is, I make my receiver not send ACK on purpose and expect the sender re-transmit after the TIMEOUT.
However, as the the recvfrom documentation says:
If no messages are available at the socket, the receive calls wait for a message to arrive, unless the socket is nonblocking.
So both my sender and receiver get stuck at sendto() and recvfrom(). They both hang! THere most be a way so that I can make the code keep running so as to achieve the TIMEOUT.
How may I do that?
Take a look at the functions select poll and epoll. They can help with the timeout. They are also very useful when waiting on mulitple file descriptors (sockets)
Set the SO_RCVTIMEO option via the setsockopt() function. Then if the timeout triggers, recvfrom() will return -1 with errno set to either EAGAIN or EWOULDBLOCK.

Is it possible (and safe) to make an accepting socket non-blocking?

I'm looking for a way to interrupt an accept() call on a blocking socket. Using signals is not an option, as this is meant to be in a library and I don't want to clutter the user signals. Using select() is another option, buf for various reason it's not very appealing in my case.
What would work well, if possible, is to set the socket to non-blocking mode (using fcntl() and O_NONBLOCK) from another thread, while the socket is blocked on an accept() call. The expected behaviour is that the accept() call will return with EAGAIN or EWOULDBLOCK in errno.
Would it indeed work like that? Is it safe? Portable?
If you know about the applicability of this method to Windows (where you need to use WSAIoctl() and FONBIO), I'm also interested.
No idea about Windows, but the behavior you want is guaranteed by POSIX:
If the listen queue is empty of connection requests and O_NONBLOCK is not set on the file descriptor for the socket, accept() shall block until a connection is present. If the listen() queue is empty of connection requests and O_NONBLOCK is set on the file descriptor for the socket, accept() shall fail and set errno to [EAGAIN] or [EWOULDBLOCK].
Source: http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html
Also, select or poll can be used to check for incoming connections by polling for the listening socket in the reading set.
In the question, You are saying that you do not want to use select (or poll or epoll) which are the best ways for IO multiplexing. I would recommend you using one another thread just for listening sockets while this is a bad idea!

epoll recv return value

I'm using epoll as level triggered. According to recv(3), if recv returns 0 "no messages are available to be received and the peer has performed an orderly shutdown". Does this mean that the whole request has been received and the socket has been closed on the other side? That the socket has been closed on both ends? Or that simply the whole request has been received and the socket is awaiting a response to be written to it? Any help would be greatly appreciated.
According to What value will recv() return, it sounds like if recv returns 0, the connection is closed on the other side. If this is the case, what needs to be done on the epoll side? Does the socket need to be completely removed with a call to epoll_ctl with EPOLL_CTL_DEL and a call to close?
It means that you have already read all the data that has been sent overthe connection, and the only thing left is a TCP FIN, which could be the result of either a full close by the remote or a shutdown for output by the remote. You can't do much but close the socket at this point, unless you know the peer has only shutdown, in which case you can still write to the socket. Your application protocol determines all that.
There is no such thing as a request or response in TCP. There is just a bidirectional byte-stream.

close vs shutdown socket?

In C, I understood that if we close a socket, it means the socket will be destroyed and can be re-used later.
How about shutdown? The description said it closes half of a duplex connection to that socket. But will that socket be destroyed like close system call?
This is explained in Beej's networking guide. shutdown is a flexible way to block communication in one or both directions. When the second parameter is SHUT_RDWR, it will block both sending and receiving (like close). However, close is the way to actually destroy a socket.
With shutdown, you will still be able to receive pending data the peer already sent (thanks to Joey Adams for noting this).
None of the existing answers tell people how shutdown and close works at the TCP protocol level, so it is worth to add this.
A standard TCP connection gets terminated by 4-way finalization:
Once a participant has no more data to send, it sends a FIN packet to the other
The other party returns an ACK for the FIN.
When the other party also finished data transfer, it sends another FIN packet
The initial participant returns an ACK and finalizes transfer.
However, there is another "emergent" way to close a TCP connection:
A participant sends an RST packet and abandons the connection
The other side receives an RST and then abandon the connection as well
In my test with Wireshark, with default socket options, shutdown sends a FIN packet to the other end but it is all it does. Until the other party send you the FIN packet you are still able to receive data. Once this happened, your Receive will get an 0 size result. So if you are the first one to shut down "send", you should close the socket once you finished receiving data.
On the other hand, if you call close whilst the connection is still active (the other side is still active and you may have unsent data in the system buffer as well), an RST packet will be sent to the other side. This is good for errors. For example, if you think the other party provided wrong data or it refused to provide data (DOS attack?), you can close the socket straight away.
My opinion of rules would be:
Consider shutdown before close when possible
If you finished receiving (0 size data received) before you decided to shutdown, close the connection after the last send (if any) finished.
If you want to close the connection normally, shutdown the connection (with SHUT_WR, and if you don't care about receiving data after this point, with SHUT_RD as well), and wait until you receive a 0 size data, and then close the socket.
In any case, if any other error occurred (timeout for example), simply close the socket.
Ideal implementations for SHUT_RD and SHUT_WR
The following haven't been tested, trust at your own risk. However, I believe this is a reasonable and practical way of doing things.
If the TCP stack receives a shutdown with SHUT_RD only, it shall mark this connection as no more data expected. Any pending and subsequent read requests (regardless whichever thread they are in) will then returned with zero sized result. However, the connection is still active and usable -- you can still receive OOB data, for example. Also, the OS will drop any data it receives for this connection. But that is all, no packages will be sent to the other side.
If the TCP stack receives a shutdown with SHUT_WR only, it shall mark this connection as no more data can be sent. All pending write requests will be finished, but subsequent write requests will fail. Furthermore, a FIN packet will be sent to another side to inform them we don't have more data to send.
There are some limitations with close() that can be avoided if one uses shutdown() instead.
close() will terminate both directions on a TCP connection. Sometimes you want to tell the other endpoint that you are finished with sending data, but still want to receive data.
close() decrements the descriptors reference count (maintained in file table entry and counts number of descriptors currently open that are referring to a file/socket) and does not close the socket/file if the descriptor is not 0. This means that if you are forking, the cleanup happens only after reference count drops to 0. With shutdown() one can initiate normal TCP close sequence ignoring the reference count.
Parameters are as follows:
int shutdown(int s, int how); // s is socket descriptor
int how can be:
SHUT_RD or 0
Further receives are disallowed
SHUT_WR or 1
Further sends are disallowed
SHUT_RDWR or 2
Further sends and receives are disallowed
This may be platform specific, I somehow doubt it, but anyway, the best explanation I've seen is here on this msdn page where they explain about shutdown, linger options, socket closure and general connection termination sequences.
In summary, use shutdown to send a shutdown sequence at the TCP level and use close to free up the resources used by the socket data structures in your process. If you haven't issued an explicit shutdown sequence by the time you call close then one is initiated for you.
I've also had success under linux using shutdown() from one pthread to force another pthread currently blocked in connect() to abort early.
Under other OSes (OSX at least), I found calling close() was enough to get connect() fail.
"shutdown() doesn't actually close the file descriptor—it just changes its usability. To free a socket descriptor, you need to use close()."1
Close
When you have finished using a socket, you can simply close its file descriptor with close; If there is still data waiting to be transmitted over the connection, normally close tries to complete this transmission. You can control this behavior using the SO_LINGER socket option to specify a timeout period; see Socket Options.
ShutDown
You can also shut down only reception or transmission on a connection by calling shutdown.
The shutdown function shuts down the connection of socket. Its argument how specifies what action to perform:
0
Stop receiving data for this socket. If further data arrives, reject it.
1
Stop trying to transmit data from this socket. Discard any data waiting to be sent. Stop looking for acknowledgement of data already sent; don’t retransmit it if it is lost.
2
Stop both reception and transmission.
The return value is 0 on success and -1 on failure.
in my test.
close will send fin packet and destroy fd immediately when socket is not shared with other processes
shutdown SHUT_RD, process can still recv data from the socket, but recv will return 0 if TCP buffer is empty.After peer send more data, recv will return data again.
shutdown SHUT_WR will send fin packet to indicate the Further sends are disallowed. the peer can recv data but it will recv 0 if its TCP buffer is empty
shutdown SHUT_RDWR (equal to use both SHUT_RD and SHUT_WR) will send rst packet if peer send more data.
linux: shutdown() causes listener thread select() to awake and produce error. shutdown(); close(); will lead to endless wait.
winsock: vice versa - shutdown() has no effect, while close() is successfully catched.

Resources