以下两个示例说明启动和接受 Internet 系列流连接。
以下是针对服务器的示例程序。服务器创建套接字并将名称绑定到此套接字,然后显示端口号。此程序调用 listen(3SOCKET) 将套接字标记为可以接受连接请求并初始化请求队列。此程序的其余部分为一个死循环。每次循环都接受一个新的连接并将其从队列中删除,从而创建一个新的套接字。服务器读取并显示此套接字中的消息,然后关闭此套接字。地址绑定中介绍了 in6addr_any 用法。
#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)); 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, sizeof(buf))) == -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); }
要启动连接,示例 7–2 中的客户机程序会创建一个流套接字,然后调用 connect(3SOCKET),指定用于连接的套接字地址。如果存在目标套接字,并且接受了请求,则连接会完成。现在,程序可以发送数据。数据按顺序传送,并且没有消息边界。此连接会在任何一个套接字关闭时销毁。有关此程序中的数据表示例程(如 ntohl(3SOCKET)、ntohs(3SOCKET)、htons(3SOCKET) 以及 htonl(3XNET))的更多信息,请参见 byteorder(3SOCKET) 手册页。
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #define DATA "Half a league, half a league . . ." /* * This program creates a socket and initiates a connection with * the socket given in the command line. Some data are sent over the * connection and then the socket is closed, ending the connection. * The form of the command line is: streamwrite hostname portnumber * Usage: pgm host port */ main(int argc, char *argv[]) { int sock, errnum, h_addr_index; struct sockaddr_in6 server; struct hostent *hp; char buf[1024]; /* Create socket. */ sock = socket( AF_INET6, SOCK_STREAM, 0); if (sock == -1) { perror("opening stream socket"); exit(1); } /* Connect socket using name specified by command line. */ bzero (&server, sizeof (server)); server.sin6_family = AF_INET6; hp = getipnodebyname(argv[1], AF_INET6, AI_DEFAULT, &errnum); /* * getipnodebyname returns a structure including the network address * of the specified host. */ if (hp == (struct hostent *) 0) { fprintf(stderr, "%s: unknown host\n", argv[1]); exit(2); } h_addr_index = 0; while (hp->h_addr_list[h_addr_index] != NULL) { bcopy(hp->h_addr_list[h_addr_index], &server.sin6_addr, hp->h_length); server.sin6_port = htons(atoi(argv[2])); if (connect(sock, (struct sockaddr *) &server, sizeof (server)) == -1) { if (hp->h_addr_list[++h_addr_index] != NULL) { /* Try next address */ continue; } perror("connecting stream socket"); freehostent(hp); exit(1); } break; } freehostent(hp); if (write( sock, DATA, sizeof DATA) == -1) perror("writing on stream socket"); close(sock); freehostent (hp); exit(0); }
可以将一对一 SCTP 连接支持添加到流套接字。以下示例代码将 -p 添加到现有程序,使此程序可以指定要使用的协议。
#include <stdio.h> #include <netdb.h> #include <string.h> #include <errno.h> int main(int argc, char *argv[]) { struct protoent *proto = NULL; int c; int s; int protocol; while ((c = getopt(argc, argv, "p:")) != -1) { switch (c) { case 'p': proto = getprotobyname(optarg); if (proto == NULL) { fprintf(stderr, "Unknown protocol: %s\n", optarg); return (-1); } break; default: fprintf(stderr, "Unknown option: %c\n", c); return (-1); } } /* Use the default protocol, which is TCP, if not specified. */ if (proto == NULL) protocol = 0; else protocol = proto->p_proto; /* Create a IPv6 SOCK_STREAM socket of the protocol. */ if ((s = socket(AF_INET6, SOCK_STREAM, protocol)) == -1) { fprintf(stderr, "Cannot create SOCK_STREAM socket of type %s: " "%s\n", proto != NULL ? proto->p_name : "tcp", strerror(errno)); return (-1); } printf("Success\n"); return (0); }