数据报套接字提供了对称数据交换接口,无需建立连接。每条消息都带有目标地址。下图显示了服务器与客户机之间的通信流。
服务器的 bind(3SOCKET) 步骤为可选步骤。
按照创建套接字中所述创建数据报套接字。如果需要特定本地地址,必须在首次数据传输之前执行 bind(3SOCKET) 操作。否则,系统会在首次发送数据时设置本地地址或端口。可以使用 sendto(3SOCKET) 发送数据。
sendto(s, buf, buflen, flags, (struct sockaddr *) &to, tolen);
s、buf、buflen 以及 flags 参数与面向连接的套接字中的相应参数相同。to 和 tolen 值指示消息预定接受者的地址。在本地检测到的错误情况(如无法访问网络)会导致返回 -1,并将 errno 设置为错误号。
recvfrom(s, buf, buflen, flags, (struct sockaddr *) &from, &fromlen);
要在数据报套接字上接收消息,请使用 recvfrom(3SOCKET)。在调用之前,fromlen 将会设置为 from 缓冲区的大小。返回时,fromlen 将会设置为接收数据报时的源地址的大小。
数据报套接字还可以使用 connect(3SOCKET) 调用将套接字与特定目标地址关联。然后,此套接字便可以使用 send(3SOCKET) 调用。如果在未显式指定目标地址的套接字上发送数据,则目标地址为已连接的对等方。只传送从该对等方接收的数据。一个套接字一次只能有一个已连接的地址。再次调用 connect(3SOCKET) 会更改目标地址。将立即返回数据报套接字上的连接请求。系统将记录对等方的地址。不能将 accept(3SOCKET) 或 listen(3SOCKET) 用于数据报套接字。
连接数据报套接字之后,便可以从先前的 send(3SOCKET) 调用中异步返回错误。此套接字可以在后续套接字操作中报告这些错误。或者,此套接字可以使用 getsockopt(3SOCKET) 的选项 SO_ERROR 来询问错误状态。
以下示例代码说明如何通过创建一个套接字、将名称绑定到该套接字以及将消息发送到该套接字来发送 Internet 调用。
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #define DATA "The sea is calm, the tide is full . . ." /* * Here I send a datagram to a receiver whose name I get from * the command line arguments. The form of the command line is: * dgramsend hostname portnumber */ main(int argc, char *argv[]) { int sock, errnum; struct sockaddr_in6 name; struct hostent *hp; /* Create socket on which to send. */ sock = socket(AF_INET6,SOCK_DGRAM, 0); if (sock == -1) { perror("opening datagram socket"); exit(1); } /* * Construct name, with no wildcards, of the socket to ``send'' * to. getinodebyname returns a structure including the network * address of the specified host. The port number is taken from * the command line. */ hp = getipnodebyname(argv[1], AF_INET6, AI_DEFAULT, &errnum); if (hp == (struct hostent *) 0) { fprintf(stderr, "%s: unknown host\n", argv[1]); exit(2); } bzero (&name, sizeof (name)); memcpy((char *) &name.sin6_addr, (char *) hp->h_addr, hp->h_length); name.sin6_family = AF_INET6; name.sin6_port = htons(atoi(argv[2])); /* Send message. */ if (sendto(sock,DATA, sizeof DATA ,0, (struct sockaddr *) &name,sizeof name) == -1) perror("sending datagram message"); close(sock); exit(0); }
以下样例代码说明如何通过创建套接字,将名称绑定到套接字然后从套接字进行读取来读取 Internet 调用。
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> /* * This program creates a datagram socket, binds a name to it, then * reads from the socket. */ main() { int sock, length; struct sockaddr_in6 name; char buf[1024]; /* Create socket from which to read. */ sock = socket(AF_INET6, SOCK_DGRAM, 0); if (sock == -1) { perror("opening datagram socket"); exit(1); } /* Create name with wildcards. */ bzero (&name, sizeof (name)); name.sin6_family = AF_INET6; name.sin6_addr = in6addr_any; name.sin6_port = 0; if (bind (sock, (struct sockaddr *)&name, sizeof (name)) == -1) { perror("binding datagram socket"); exit(1); } /* Find assigned port value and print it out. */ length = sizeof(name); if (getsockname(sock,(struct sockaddr *) &name, &length) == -1) { perror("getting socket name"); exit(1); } printf("Socket port #%d\n", ntohs(name.sin6_port)); /* Read from the socket. */ if (read(sock, buf, 1024) == -1 ) perror("receiving datagram packet"); /* Assumes the data is printable */ printf("-->%s\n", buf); close(sock); exit(0); }