Unix Network Programming Manual
Sending and Receiving
The actual passing of data is done in a manner similar to reading and
writing a file. There are some differences between stream and datagram
sockets, so stream sockets will be discussed here.
For example, to send data to the other end of a
connection, use:
count = send (sock, buf, len, flags)
int count, sock
char *buf
int len, flags
The return value is the number of bytes actually sent or -1 if an error
occurs. sock is the socket, buf is the buffer of bytes to
send and len is the length of buf in bytes. flags allows
certain special operations to take place and they will be discussed later.
If no special flags are needed, pass the flags value as zero.
There is no special format for buf - it is simply a string of bytes.
However, it is not uncommon for there to be an overlying logical format that
makes sense to the sender and (hopefully) the receiver. For example,
msg could be a string of characters representing a sentence of English text,
or it could be a set of binary integer values moved into msg.
The format depends on the higher level protocol defined by the client-server
protocol. For example:
int count, sock
char *buf
int len;
short value [50]
.
.
send (sock, value, (int)(2*50), 0);
sends 50 two-byte short integers to the socket. This is not the best
way to do this, as will be pointed out later.
To receive data, use a call of the form:
count = recv (sock, msg, len, flags)
int count, sock
char *msg
int len, flags
Everything is the same as in the send call, except that count is the number
of bytes received from the connection. The len parameter indicates
the maximum length of data that can be returned, so the number of bytes
returned in msg will be len or less. It is not necessary to know exactly
how many bytes are incoming.
recv is normally a blocking
call, which means it waits until data is available before returning. If
the other end of your connection does not send anything, your program will
wait forever. One exception to this is if the other end has closed the
connection. In the case of AF_UNIX communication, the recv will return zero
indicating an end-of-file. However, communication between different
machines will not provide this service. This is one of the reasons that
communication protocols often include timers to interrupt receives that
wait too long. There are a number of more sophisticated ways to handle
incoming data, such as using interrupt-driven I/O and non-blocking
receives. These advanced topics will be discussed later.
Stream communications can be tricky for beginners because it typically
ignores boundaries (there are lots of different implementations of these
methods, so nothing is absolute). That means that if you were to send
two messages to the other end of a connection, it might receive them all
in one piece, in two different pieces, or in more than two pieces. For
example, if the sender executed (Note that the null character at the end
of the string is not included in the message):
send (sock, "Message 1", 9, 0);
send (sock, "Message 2", 9, 0);
and the receiver executed:
count = recv (sock, buf, 80, 0);
The receiver might get "Message 1Message 2", or "Message 1Mess" or
"Mess". For a stream connection, the operating system determines how
much is sent and at what intervals. This can be an inconvenience at
times, but has other properties that make it acceptable.