データグラムソケットは、コネクションの確立を要求せずに、対称型データ交換インタフェースを提供します。各メッセージには着信先アドレスが含まれます。次の図では、サーバーとクライアント間の通信の流れを示します。
次の図において、サーバー側の 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) 呼び出しを使用できます。着信先アドレスが明示的に指定されていないソケット上に送信されるデータはすべて、接続されたピアにアドレス指定されます。そして、そのピアから受信されるデータだけが配信されます。1 つのソケットに一度に接続できるのは、接続された 1 つのアドレスだけです。2 番目の connect(3SOCKET) 呼び出しは、着信先アドレスを変更します。データグラムソケット上のコネクション要求は、すぐに返されます。システムは、ピアのアドレスを記録します。accept(3SOCKET) と listen(3SOCKET) はデータグラムソケットでは使用されません。
データグラムソケットが接続されている間、前の send(3SOCKET) 呼び出しからのエラーは非同期に返すことができます。ソケットはこれらのエラーを後続の操作で報告できます。また、getsockopt(3SOCKET) のオプションである SO_ERROR を使用して、エラー状態を問い合わせることもできます。
次のコードに、ソケットの作成、名前のバインド、ソケットへのメッセージ送信によって、インターネット呼び出しを送信する例を示します。
#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); }
次のコードに、ソケットの作成、名前のバインド、ソケットからのメッセージ読み取りによって、インターネット呼び出しを読み取る例を示します。
#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); }