ソケットプログラミング
ソケット: 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);
}
|