The most common communication styles involve making a connection to a particular other socket, and then exchanging data with that socket over and over. Making a connection is asymmetric; one side (the client) acts to request a connection, while the other side (the server) makes a socket and waits for the connection request.
In making a connection, the client makes a connection while the server waits for and accepts the connection. Here we discuss what the client program must do with the connect function, which is declared in sys/socket.h.
int function>connect/function> (int socket, struct sockaddr *addr, socklen_t length) The connect function initiates a connection from the socket with file descriptor socket to the socket whose address is specified by the addr and length arguments. (This socket is typically on another machine, and it must be already set up as a server.) the section called “Socket Addresses”, for information about how these arguments are interpreted.
Normally, connect waits until the server responds to the request before it returns. You can set nonblocking mode on the socket socket to make connect return immediately without waiting for the response. the section called “File Status Flags”, for information about nonblocking mode.
The normal return value from connect is 0. If an error occurs, connect returns -1. The following errno error conditions are defined for this function:
The socket socket is not a valid file descriptor.
File descriptor socket is not a socket.
The specified address is not available on the remote machine.
The namespace of the addr is not supported by this socket.
The socket socket is already connected.
The attempt to establish the connection timed out.
The server has actively refused to establish the connection.
The network of the given addr isn't reachable from this host.
The socket address of the given addr is already in use.
The socket socket is non-blocking and the connection could not be established immediately. You can determine when the connection is completely established with select; the section called “Waiting for Input or Output”. Another connect call on the same socket, before the connection is completely established, will fail with EALREADY.
The socket socket is non-blocking and already has a pending connection in progress (see EINPROGRESS above).
This function is defined as a cancellation point in multi-threaded programs, so one has to be prepared for this and make sure that allocated resources (like memory, files descriptors, semaphores or whatever) are freed even if the thread is canceled.
Now let us consider what the server process must do to accept connections on a socket. First it must use the listen function to enable connection requests on the socket, and then accept each incoming connection with a call to accept (the section called “Accepting Connections”). Once connection requests are enabled on a server socket, the select function reports when the socket has a connection ready to be accepted (the section called “Waiting for Input or Output”).
The listen function is not allowed for sockets using connectionless communication styles.
You can write a network server that does not even start running until a connection to it is requested. the section called “inetdServers”.
In the Internet namespace, there are no special protection mechanisms for controlling access to a port; any process on any machine can make a connection to your server. If you want to restrict access to your server, make it examine the addresses associated with connection requests or implement some other handshaking or identification protocol.
In the local namespace, the ordinary file protection bits control who has access to connect to the socket.
int function>listen/function> (int socket, unsigned int n) The listen function enables the socket socket to accept connections, thus making it a server socket.
The argument n specifies the length of the queue for pending connections. When the queue fills, new clients attempting to connect fail with ECONNREFUSED until the server calls accept to accept a connection from the queue.
The listen function returns 0 on success and -1 on failure. The following errno error conditions are defined for this function:
The argument socket is not a valid file descriptor.
The argument socket is not a socket.
The socket socket does not support this operation.
When a server receives a connection request, it can complete the connection by accepting the request. Use the function accept to do this.
A socket that has been established as a server can accept connection requests from multiple clients. The server's original socket does not become part of the connection; instead, accept makes a new socket which participates in the connection. accept returns the descriptor for this socket. The server's original socket remains available for listening for further connection requests.
The number of pending connection requests on a server socket is finite. If connection requests arrive from clients faster than the server can act upon them, the queue can fill up and additional requests are refused with an ECONNREFUSED error. You can specify the maximum length of this queue as an argument to the listen function, although the system may also impose its own internal limit on the length of this queue.
int function>accept/function> (int socket, struct sockaddr *addr, socklen_t *length_ptr) This function is used to accept a connection request on the server socket socket.
The accept function waits if there are no connections pending, unless the socket socket has nonblocking mode set. (You can use select to wait for a pending connection, with a nonblocking socket.) the section called “File Status Flags”, for information about nonblocking mode.
The addr and length-ptr arguments are used to return information about the name of the client socket that initiated the connection. the section called “Socket Addresses”, for information about the format of the information.
Accepting a connection does not make socket part of the connection. Instead, it creates a new socket which becomes connected. The normal return value of accept is the file descriptor for the new socket.
After accept, the original socket socket remains open and unconnected, and continues listening until you close it. You can accept further connections with socket by calling accept again.
If an error occurs, accept returns -1. The following errno error conditions are defined for this function:
The socket argument is not a valid file descriptor.
The descriptor socket argument is not a socket.
The descriptor socket does not support this operation.
socket has nonblocking mode set, and there are no pending connections immediately available.
This function is defined as a cancellation point in multi-threaded programs, so one has to be prepared for this and make sure that allocated resources (like memory, files descriptors, semaphores or whatever) are freed even if the thread is canceled.
The accept function is not allowed for sockets using connectionless communication styles.
int function>getpeername/function> (int socket, struct sockaddr *addr, socklen_t *length-ptr) The getpeername function returns the address of the socket that socket is connected to; it stores the address in the memory space specified by addr and length-ptr. It stores the length of the address in *length-ptr.
the section called “Socket Addresses”, for information about the format of the address. In some operating systems, getpeername works only for sockets in the Internet domain.
The return value is 0 on success and -1 on error. The following errno error conditions are defined for this function:
The argument socket is not a valid file descriptor.
The descriptor socket is not a socket.
The socket socket is not connected.
There are not enough internal buffers available.
Once a socket has been connected to a peer, you can use the ordinary read and write operations (the section called “Input and Output Primitives”) to transfer data. A socket is a two-way communications channel, so read and write operations can be performed at either end.
There are also some I/O modes that are specific to socket operations. In order to specify these modes, you must use the recv and send functions instead of the more generic read and write functions. The recv and send functions take an additional argument which you can use to specify various flags to control special I/O modes. For example, you can specify the MSG_OOB flag to read or write out-of-band data, the MSG_PEEK flag to peek at input, or the MSG_DONTROUTE flag to control inclusion of routing information on output.
The send function is declared in the header file sys/socket.h. If your flags argument is zero, you can just as well use write instead of send; see the section called “Input and Output Primitives”. If the socket was connected but the connection has broken, you get a SIGPIPE signal for any use of send or write (the section called “Miscellaneous Signals”).
int function>send/function> (int socket, void *buffer, size_t size, int flags) The send function is like write, but with the additional flags flags. The possible values of flags are described in the section called “Socket Data Options”.
This function returns the number of bytes transmitted, or -1 on failure. If the socket is nonblocking, then send (like write) can return after sending just part of the data. the section called “File Status Flags”, for information about nonblocking mode.
Note, however, that a successful return value merely indicates that the message has been sent without error, not necessarily that it has been received without error.
The following errno error conditions are defined for this function:
The socket argument is not a valid file descriptor.
The operation was interrupted by a signal before any data was sent. the section called “Primitives Interrupted by Signals”.
The descriptor socket is not a socket.
The socket type requires that the message be sent atomically, but the message is too large for this to be possible.
Nonblocking mode has been set on the socket, and the write operation would block. (Normally send blocks until the operation can be completed.)
There is not enough internal buffer space available.
You never connected this socket.
This socket was connected but the connection is now broken. In this case, send generates a SIGPIPE signal first; if that signal is ignored or blocked, or if its handler returns, then send fails with EPIPE.
This function is defined as a cancellation point in multi-threaded programs, so one has to be prepared for this and make sure that allocated resources (like memory, files descriptors, semaphores or whatever) are freed even if the thread is canceled.
The recv function is declared in the header file sys/socket.h. If your flags argument is zero, you can just as well use read instead of recv; see the section called “Input and Output Primitives”.
int function>recv/function> (int socket, void *buffer, size_t size, int flags) The recv function is like read, but with the additional flags flags. The possible values of flags are described in the section called “Socket Data Options”.
If nonblocking mode is set for socket, and no data are available to be read, recv fails immediately rather than waiting. the section called “File Status Flags”, for information about nonblocking mode.
This function returns the number of bytes received, or -1 on failure. The following errno error conditions are defined for this function:
The socket argument is not a valid file descriptor.
The descriptor socket is not a socket.
Nonblocking mode has been set on the socket, and the read operation would block. (Normally, recv blocks until there is input available to be read.)
The operation was interrupted by a signal before any data was read. the section called “Primitives Interrupted by Signals”.
You never connected this socket.
This function is defined as a cancellation point in multi-threaded programs, so one has to be prepared for this and make sure that allocated resources (like memory, files descriptors, semaphores or whatever) are freed even if the thread is canceled.
The flags argument to send and recv is a bit mask. You can bitwise-OR the values of the following macros together to obtain a value for this argument. All are defined in the header file sys/socket.h.
int function>MSG_OOB/function> Send or receive out-of-band data. the section called “Out-of-Band Data”.
int function>MSG_PEEK/function> Look at the data but don't remove it from the input queue. This is only meaningful with input functions such as recv, not with send.
int function>MSG_DONTROUTE/function> Don't include routing information in the message. This is only meaningful with output operations, and is usually only of interest for diagnostic or routing programs. We don't try to explain it here.
Here is an example client program that makes a connection for a byte stream socket in the Internet namespace. It doesn't do anything particularly interesting once it has connected to the server; it just sends a text string to the server and exits.
This program uses init_sockaddr to set up the socket address; see the section called “Internet Socket Example”.
#include stdio.h #include errno.h #include stdlib.h #include unistd.h #include sys/types.h #include sys/socket.h #include netinet/in.h #include netdb.h #define PORT 5555 #define MESSAGE "Yow!!! Are we having fun yet?!?" #define SERVERHOST "mescaline.gnu.org" void write_to_server (int filedes) { int nbytes; nbytes = write (filedes, MESSAGE, strlen (MESSAGE) + 1); if (nbytes 0) { perror ("write"); exit (EXIT_FAILURE); } } int main (void) { extern void init_sockaddr (struct sockaddr_in *name, const char *hostname, uint16_t port); int sock; struct sockaddr_in servername; /* Create the socket. */ sock = socket (PF_INET, SOCK_STREAM, 0); if (sock 0) { perror ("socket (client)"); exit (EXIT_FAILURE); } /* Connect to the server. */ init_sockaddr (servername, SERVERHOST, PORT); if (0 connect (sock, (struct sockaddr *) servername, sizeof (servername))) { perror ("connect (client)"); exit (EXIT_FAILURE); } /* Send data to the server. */ write_to_server (sock); close (sock); exit (EXIT_SUCCESS); }
The server end is much more complicated. Since we want to allow multiple clients to be connected to the server at the same time, it would be incorrect to wait for input from a single client by simply calling read or recv. Instead, the right thing to do is to use select (the section called “Waiting for Input or Output”) to wait for input on all of the open sockets. This also allows the server to deal with additional connection requests.
This particular server doesn't do anything interesting once it has gotten a message from a client. It does close the socket for that client when it detects an end-of-file condition (resulting from the client shutting down its end of the connection).
This program uses make_socket to set up the socket address; see the section called “Internet Socket Example”.
#include stdio.h #include errno.h #include stdlib.h #include unistd.h #include sys/types.h #include sys/socket.h #include netinet/in.h #include netdb.h #define PORT 5555 #define MAXMSG 512 int read_from_client (int filedes) { char buffer[MAXMSG]; int nbytes; nbytes = read (filedes, buffer, MAXMSG); if (nbytes 0) { /* Read error. */ perror ("read"); exit (EXIT_FAILURE); } else if (nbytes == 0) /* End-of-file. */ return -1; else { /* Data read. */ fprintf (stderr, "Server: got message: `%s'\n", buffer); return 0; } } int main (void) { extern int make_socket (uint16_t port); int sock; fd_set active_fd_set, read_fd_set; int i; struct sockaddr_in clientname; size_t size; /* Create the socket and set it up to accept connections. */ sock = make_socket (PORT); if (listen (sock, 1) 0) { perror ("listen"); exit (EXIT_FAILURE); } /* Initialize the set of active sockets. */ FD_ZERO (active_fd_set); FD_SET (sock, active_fd_set); while (1) { /* Block until input arrives on one or more active sockets. */ read_fd_set = active_fd_set; if (select (FD_SETSIZE, read_fd_set, NULL, NULL, NULL) 0) { perror ("select"); exit (EXIT_FAILURE); } /* Service all the sockets with input pending. */ for (i = 0; i FD_SETSIZE; ++i) if (FD_ISSET (i, read_fd_set)) { if (i == sock) { /* Connection request on original socket. */ int new; size = sizeof (clientname); new = accept (sock, (struct sockaddr *) clientname, size); if (new 0) { perror ("accept"); exit (EXIT_FAILURE); } fprintf (stderr, "Server: connect from host %s, port %hd.\n", inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port)); FD_SET (new, active_fd_set); } else { /* Data arriving on an already-connected socket. */ if (read_from_client (i) 0) { close (i); FD_CLR (i, active_fd_set); } } } } }
Streams with connections permit out-of-band data that is delivered with higher priority than ordinary data. Typically the reason for sending out-of-band data is to send notice of an exceptional condition. To send out-of-band data use send, specifying the flag MSG_OOB (the section called “Sending Data”).
Out-of-band data are received with higher priority because the receiving process need not read it in sequence; to read the next available out-of-band data, use recv with the MSG_OOB flag (the section called “Receiving Data”). Ordinary read operations do not read out-of-band data; they read only ordinary data.
When a socket finds that out-of-band data are on their way, it sends a SIGURG signal to the owner process or process group of the socket. You can specify the owner using the F_SETOWN command to the fcntl function; see the section called “Interrupt-Driven Input”. You must also establish a handler for this signal, as described in Chapter 25, in order to take appropriate action such as reading the out-of-band data.
Alternatively, you can test for pending out-of-band data, or wait until there is out-of-band data, using the select function; it can wait for an exceptional condition on the socket. the section called “Waiting for Input or Output”, for more information about select.
Notification of out-of-band data (whether with SIGURG or with select) indicates that out-of-band data are on the way; the data may not actually arrive until later. If you try to read the out-of-band data before it arrives, recv fails with an EWOULDBLOCK error.
Sending out-of-band data automatically places a "mark" in the stream of ordinary data, showing where in the sequence the out-of-band data "would have been". This is useful when the meaning of out-of-band data is "cancel everything sent so far". Here is how you can test, in the receiving process, whether any ordinary data was sent before the mark:
success = ioctl (socket, SIOCATMARK, atmark);
The integer variable atmark is set to a nonzero value if the socket's read pointer has reached the "mark".
Here's a function to discard any ordinary data preceding the out-of-band mark:
int discard_until_mark (int socket) { while (1) { /* This is not an arbitrary limit; any size will do. */ char buffer[1024]; int atmark, success; /* If we have reached the mark, return. */ success = ioctl (socket, SIOCATMARK, atmark); if (success 0) perror ("ioctl"); if (result) return; /* Otherwise, read a bunch of ordinary data and discard it. This is guaranteed not to read past the mark if it starts before the mark. */ success = read (socket, buffer, sizeof buffer); if (success 0) perror ("read"); } }
If you don't want to discard the ordinary data preceding the mark, you may need to read some of it anyway, to make room in internal system buffers for the out-of-band data. If you try to read out-of-band data and get an EWOULDBLOCK error, try reading some ordinary data (saving it so that you can use it when you want it) and see if that makes room. Here is an example:
struct buffer { char *buf; int size; struct buffer *next; }; /* Read the out-of-band data from SOCKET and return it as a `struct buffer', which records the address of the data and its size. It may be necessary to read some ordinary data in order to make room for the out-of-band data. If so, the ordinary data are saved as a chain of buffers found in the `next' field of the value. */ struct buffer * read_oob (int socket) { struct buffer *tail = 0; struct buffer *list = 0; while (1) { /* This is an arbitrary limit. Does anyone know how to do this without a limit? */ #define BUF_SZ 1024 char *buf = (char *) xmalloc (BUF_SZ); int success; int atmark; /* Try again to read the out-of-band data. */ success = recv (socket, buf, BUF_SZ, MSG_OOB); if (success = 0) { /* We got it, so return it. */ struct buffer *link = (struct buffer *) xmalloc (sizeof (struct buffer)); link-buf = buf; link-size = success; link-next = list; return link; } /* If we fail, see if we are at the mark. */ success = ioctl (socket, SIOCATMARK, atmark); if (success 0) perror ("ioctl"); if (atmark) { /* At the mark; skipping past more ordinary data cannot help. So just wait a while. */ sleep (1); continue; } /* Otherwise, read a bunch of ordinary data and save it. This is guaranteed not to read past the mark if it starts before the mark. */ success = read (socket, buf, BUF_SZ); if (success 0) perror ("read"); /* Save this data in the buffer list. */ { struct buffer *link = (struct buffer *) xmalloc (sizeof (struct buffer)); link-buf = buf; link-size = success; /* Add the new link to the end of the list. */ if (tail) tail-next = link; else list = link; tail = link; } } }