ソケットプログラミング
ソケット: Socket。TCP/IP アプリケーションを作成するための抽象化されたインターフェース。
インターネット電話やインターネット放送を含むすべての TCP/IP アプリケーション。
まずは sockaddr_in 構造体に適切なパラメータ設定を行い、以下のソケット関数を実行する。
共通 | |
socket | ソケットの作成 |
bind | ソケットとポートの結合 |
setsockopt | ソケットオプションの設定 |
close (Linux), closesocket (Win) | ソケットの終了 |
htonl | ホスト・バイトオーダーをネットワーク・バイトオーダーに変換 (4バイト) |
htons | ホスト・バイトオーダーをネットワーク・バイトオーダーに変換 (2バイト) |
ntohl | ネットワーク・バイトオーダーをホスト・バイトオーダーに変換 (4バイト) |
ntohs | ネットワーク・バイトオーダーをホスト・バイトオーダーに変換 (2バイト) |
inet_addr | 文字列をIPアドレスに変換 |
inet_ntoa | IPアドレスを文字列に変換 |
TCP | |
listen | 接続キューの作成 (サーバ側) |
accept | 接続受入れ (サーバ側) |
connect | サーバへの接続 (クライアント側) |
send | パケット送信 |
recv | パケット受信 |
UDP | |
sendto | パケット送信 |
recvfrom | パケット受信 |
以下は、クライアントがサーバに接続し、1秒ごとにメッセージを送信するプログラムである (ただし、エラー処理をまったく行っていない悪いプログラムである)。まずサーバ側を起動し、別のマシンでクライアント側を起動する。Windows 用と Linux 用のプログラムの違いはほとんどなく、
インクルードするヘッダファイル | |
Windows で TCP/IP を有効にするための WSA 関数 | |
ソケット終了のための closesocket (Windows) と close (Linux) の違い |
しかない。言いかえれば、ソケットは OS に依存しない関数群である。
Windows版: リンクオプションに ws2_32.lib を加える。
TCP サーバ側
#include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> #define BUFFER_SIZE 256 int main() { /* ポート番号、ソケット */ unsigned short port = 9876; int srcSocket; // 自分 int dstSocket; // 相手 /* sockaddr_in 構造体 */ struct sockaddr_in srcAddr; struct sockaddr_in dstAddr; int dstAddrSize = sizeof(dstAddr); /* 各種パラメータ */ int numrcv; char buffer[BUFFER_SIZE]; /************************************************************/ /* Windows 独自の設定 */ WSADATA data; WSAStartup(MAKEWORD(2,0), &data); /* sockaddr_in 構造体のセット */ memset(&srcAddr, 0, sizeof(srcAddr)); srcAddr.sin_port = htons(port); srcAddr.sin_family = AF_INET; srcAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* ソケットの生成 */ srcSocket = socket(AF_INET, SOCK_STREAM, 0); /* ソケットのバインド */ bind(srcSocket, (struct sockaddr *) &srcAddr, sizeof(srcAddr)); /* 接続の許可 */ listen(srcSocket, 1); /* 接続の受付け */ printf("Waiting for connection ...\n"); dstSocket = accept(srcSocket, (struct sockaddr *) &dstAddr, &dstAddrSize); printf("Connected from %s\n", inet_ntoa(dstAddr.sin_addr)); /* パケット受信 */ while(1) { numrcv = recv(dstSocket, buffer, BUFFER_SIZE, 0); if(numrcv == 0 || numrcv == -1) { status = closesocket(dstSocket); break; } printf("received: %s\n", buffer); } /* Windows 独自の設定 */ WSACleanup(); } |
TCP クライアント側
#include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> int main() { /* IP アドレス、ポート番号、ソケット */ char destination[80]; unsigned short port = 9876; int dstSocket; /* sockaddr_in 構造体 */ struct sockaddr_in dstAddr; /* 各種パラメータ */ int status; int numsnt; char *toSendText = "This is a test"; /************************************************************/ /* Windows 独自の設定 */ WSADATA data; WSAStartup(MAKEWORD(2,0), &data)); /* 相手先アドレスの入力 */ printf("Connect to ? : (name or IP address) "); scanf("%s", destination); /* sockaddr_in 構造体のセット */ memset(&dstAddr, 0, sizeof(dstAddr)); dstAddr.sin_port = htons(port); dstAddr.sin_family = AF_INET; stAddr.sin_addr.s_addr = inet_addr(destination); /* ソケット生成 */ dstSocket = socket(AF_INET, SOCK_STREAM, 0); /* 接続 */ printf("Trying to connect to %s: \n", destination); connect(dstSocket, (struct sockaddr *) &dstAddr, sizeof(dstAddr)); /* パケット送出 */ for(i=0; i<10; i++) { printf("sending...\n"); send(dstSocket, toSendText, strlen(toSendText)+1, 0); Sleep(1000); } /* Windows 独自の設定 */ closesocket(dstSocket); WSACleanup(); } |
UDP サーバ側
#include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> #define BUFFER_SIZE 256 int main() { /* ポート番号、ソケット */ int port = 9876; int recvSocket; /* sockaddr_in 構造体 */ struct sockaddr_in recvSockAddr; /* 各種パラメータ */ int status; int numrcv; char buffer[BUFFER_SIZE]; unsigned long on = 1; /************************************************************/ /* Windows 独自の設定 */ WSADATA data; WSAStartup(MAKEWORD(2,0), &data)); /* sockaddr_in 構造体のセット */ memset(&recvSockAddr, 0, sizeof(recvSockAddr)); recvSockAddr.sin_port = htons(port); recvSockAddr.sin_family = AF_INET; recvSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* ソケット生成 */ recvSocket = socket(AF_INET, SOCK_DGRAM, 0); /* バインド */ status = bind(recvSocket, (struct sockaddr_in *) &recvSockAddr, sizeof(recvSockAddr)); /* パケット受信 */ while(1) { numrcv = recvfrom(recvSocket, buffer, BUFFER_SIZE, 0, NULL, NULL); if(numrcv == -1) { status = closesocket(recvSocket); break; } printf("received: %s\n", buffer); } /* Windows 独自の設定 */ WSACleanup(); } |
UDP クライアント側
#include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> int main() { /* IPアドレス、ポート番号、ソケット */ char destination[80]; unsgined short port = 9876; int destSocket; /* sockaddr_in 構造体 */ struct sockaddr_in destSockAddr; /* 各種パラメータ */ int i; char *toSendText = "This is a test"; /************************************************************/ /* Windows 独自の設定 */ WSADATA data; WSAStartup(MAKEWORD(2,0), &data)); /* 相手先アドレスの入力 */ printf("Connect to ? : (name or IP address) "); scanf("%s", destination); /* sockaddr_in 構造体のセット */ memset(&destSockAddr, 0, sizeof(destSockAddr)); destSockAddr.sin_addr.s_addr = inet_addr(destination); destSockAddr.sin_port = htons(port); destSockAddr.sin_family = AF_INET; /* ソケット生成 */ destSocket = socket(AF_INET, SOCK_DGRAM, 0); /* パケット送出 */ for(i=0; i<10; i++) { printf("sending...\n"); sendto(destSocket, toSendText, strlen(toSendText)+1, 0, &destSockAddr, sizeof(destSockAddr)); Sleep(1000); } /* Windows 独自の設定 */ closesocket(destSocket); WSACleanup(); } |
Linux版: コンパイルは "gcc ソース名 -lsocket" とする。
TCP サーバ側
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define BUFFER_SIZE 256 int main() { /* ポート番号、ソケット */ unsigned short port = 9876; int srcSocket; // 自分 int dstSocket; // 相手 /* sockaddr_in 構造体 */ struct sockaddr_in srcAddr; struct sockaddr_in dstAddr; int dstAddrSize = sizeof(dstAddr); /* 各種パラメータ */ int numrcv; char buffer[BUFFER_SIZE]; /************************************************************/ /* sockaddr_in 構造体のセット */ memset(&srcAddr, 0, sizeof(srcAddr)); srcAddr.sin_port = htons(port); srcAddr.sin_family = AF_INET; srcAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* ソケットの生成 */ srcSocket = socket(AF_INET, SOCK_STREAM, 0); /* ソケットのバインド */ bind(srcSocket, (struct sockaddr *) &srcAddr, sizeof(srcAddr)); /* 接続の許可 */ listen(srcSocket, 1); /* 接続の受付け */ printf("Waiting for connection ...\n"); dstSocket = accept(srcSocket, (struct sockaddr *) &dstAddr, &dstAddrSize); printf("Connected from %s\n", inet_ntoa(dstAddr.sin_addr)); /* パケット受信 */ while(1) { numrcv = recv(dstSocket, buffer, BUFFER_SIZE, 0); if(numrcv == 0 || numrcv == -1) { status = close(dstSocket); break; } printf("received: %s\n", buffer); } } |
TCP クライアント側
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> int main() { /* IP アドレス、ポート番号、ソケット */ char destination[80]; unsigned short port = 9876; int dstSocket; /* sockaddr_in 構造体 */ struct sockaddr_in dstAddr; /* 各種パラメータ */ int status; int numsnt; char *toSendText = "This is a test"; /************************************************************/ /* 相手先アドレスの入力 */ printf("Connect to ? : (name or IP address) "); scanf("%s", destination); /* sockaddr_in 構造体のセット */ memset(&dstAddr, 0, sizeof(dstAddr)); dstAddr.sin_port = htons(port); dstAddr.sin_family = AF_INET; stAddr.sin_addr.s_addr = inet_addr(destination); /* ソケット生成 */ dstSocket = socket(AF_INET, SOCK_STREAM, 0); /* 接続 */ printf("Trying to connect to %s: \n", destination); connect(dstSocket, (struct sockaddr *) &dstAddr, sizeof(dstAddr)); /* パケット送出 */ for(i=0; i<10; i++) { printf("sending...\n"); send(dstSocket, toSendText, strlen(toSendText)+1, 0); sleep(1); } /* ソケット終了 */ close(dstSocket); } |
UDP サーバ側
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define BUFFER_SIZE 256 int main() { /* ポート番号、ソケット */ unsigned short port = 9876; int recvSocket; /* sockaddr_in 構造体 */ struct sockaddr_in recvSockAddr; /* 各種パラメータ */ int status; int numrcv; char buffer[BUFFER_SIZE]; unsigned long on = 1; /************************************************************/ /* sockaddr_in 構造体のセット */ memset(&recvSockAddr, 0, sizeof(recvSockAddr)); recvSockAddr.sin_port = htons(port); recvSockAddr.sin_family = AF_INET; recvSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* ソケット生成 */ recvSocket = socket(AF_INET, SOCK_DGRAM, 0); /* バインド */ status = bind(recvSocket, (struct sockaddr_in *) &recvSockAddr, sizeof(recvSockAddr)); /* パケット受信 */ while(1) { numrcv = recvfrom(recvSocket, buffer, BUFFER_SIZE, 0, NULL, NULL); if(numrcv == -1) { status = close(recvSocket); break; } printf("received: %s\n", buffer); } } |
UDP クライアント側
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> int main() { /* IPアドレス、ポート番号、ソケット */ char destination[80]; unsgined short port = 9876; int destSocket; /* sockaddr_in 構造体 */ struct sockaddr_in destSockAddr; /* 各種パラメータ */ int i; char *toSendText = "This is a test"; /************************************************************/ /* 相手先アドレスの入力 */ printf("Connect to ? : (name or IP address) "); scanf("%s", destination); /* sockaddr_in 構造体のセット */ memset(&destSockAddr, 0, sizeof(destSockAddr)); destSockAddr.sin_addr.s_addr = inet_addr(destination); destSockAddr.sin_port = htons(port); destSockAddr.sin_family = AF_INET; /* ソケット生成 */ destSocket = socket(AF_INET, SOCK_DGRAM, 0); /* パケット送出 */ for(i=0; i<10; i++) { printf("sending...\n"); sendto(destSocket, toSendText, strlen(toSendText)+1, 0, &destSockAddr, sizeof(destSockAddr)); sleep(1); } /* ソケットの終了 */ close(destSocket); } |