Data Transfer
This section describes the interfaces to send and receive data. You can send or receive a message with the normal read(2) and write(2) interfaces:
write(s, buf, sizeof buf); read(s, buf, sizeof buf); |
You can also use send(3SOCKET) and recv(3SOCKET):
send(s, buf, sizeof buf, flags); recv(s, buf, sizeof buf, flags); |
send(3SOCKET) and recv(3SOCKET) are very similar to read(2) and write(2), but the flags argument is important. The flags, defined in sys/socket.h, can be specified as a nonzero value if one or more of the following is required:
MSG_OOB | Send and receive out-of-band data |
MSG_PEEK | Look at data without reading |
MSG_DONTROUTE | Send data without routing packets |
Out-of-band data is specific to stream sockets. When MSG_PEEK is specified with a recv(3SOCKET) call, any data present is returned to the user, but treated as still unread. The next read(2) or recv(3SOCKET) call on the socket returns the same data. The option to send data without routing packets applied to the outgoing packets is currently used only by the routing table management process.
Closing Sockets
A SOCK_STREAM socket can be discarded by a close(2) interface call. If data is queued to a socket that promises reliable delivery after a close(2), the protocol continues to try to transfer the data. If the data remains undelivered after an arbitrary period, it is discarded.
A shutdown(3SOCKET) closes SOCK_STREAM sockets gracefully. Both processes can acknowledge that they are no longer sending. This call has the form:
shutdown(s, how); |
where how is defined as
0 | Disallows further data reception |
1 | Disallows further data transmission |
2 | Disallows further transmission and reception |
Connecting Stream Sockets
The following two examples illustrate initiating and accepting an Internet family stream connection.
Figure 6-1 Connection-Oriented Communication Using Stream Sockets
The following example program is a server. It creates a socket and binds a name to the socket, then displays the port number. The program calls listen(3SOCKET) to mark the socket as ready to accept connection requests and initialize a queue for the requests. The rest of the program is an infinite loop. Each pass of the loop accepts a new connection and removes it from the queue, creating a new socket. The server reads and displays the messages from the socket and closes it. The use of in6addr_any is explained in "Address Binding".
Example 6-1 Accepting an Internet Stream Connection (Server)
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include >stdio.h> #define TRUE 1 /* * This program creates a socket and then begins an infinite loop. * Each time through the loop it accepts a connection and prints * data from it. When the connection breaks, or the client closes * the connection, the program accepts a new connection. */ main() { int sock, length; struct sockaddr_in6 server; int msgsock; char buf[1024]; int rval; /* Create socket. */ sock = socket(AF_INET6, SOCK_STREAM, 0); if (sock == -1) { perror("opening stream socket"); exit(1); } /* Bind socket using wildcards.*/ bzero (&server, sizeof(server)); /* bzero (&sin6, sizeof (sin6)); */ server.sin6_family = AF_INET6; server.sin6_addr = in6addr_any; server.sin6_port = 0; if (bind(sock, (struct sockaddr *) &server, sizeof server) == -1) { perror("binding stream socket"); exit(1); } /* Find out assigned port number and print it out. */ length = sizeof server; if (getsockname(sock,(struct sockaddr *) &server, &length) == -1) { perror("getting socket name"); exit(1); } printf("Socket port #%d\n", ntohs(server.sin6_port)); /* Start accepting connections. */ listen(sock, 5); do { msgsock = accept(sock,(struct sockaddr *) 0,(int *) 0); if (msgsock == -1) perror("accept"); else do { memset(buf, 0, sizeof buf); if ((rval = read(msgsock,buf, 1024)) == -1) perror("reading stream message"); if (rval == 0) printf("Ending connection\n"); else /* assumes the data is printable */ printf("-->%s\n", buf); } while (rval > 0); close(msgsock); } while(TRUE); /* * Since this program has an infinite loop, the socket "sock" is * never explicitly closed. However, all sockets are closed * automatically when a process is killed or terminates normally. */ exit(0); } |
To initiate a connection, the client program in Example 6-2 creates a stream socket and calls connect(3SOCKET), specifying the address of the socket for connection. If the target socket exists and the request is accepted, the connection is complete and the program can send data. Data is delivered in sequence with no message boundaries. The connection is destroyed when either socket is closed. For more information about data representation routines in this program, such as ntohl(3SOCKET), ntohs(3SOCKET), htons(3SOCKET), and htonl(3XNET), see the byteorder(3SOCKET) man page.
Example 6-2 Internet Family Stream Connection (Client)