こんにちは。
TCP/IP でのソケットを用いたデータ通信の仕組みに関して改めて勉強してみたので、自分自身の理解のために簡単なデータロガープログラムを書いてみました。
※ いつも通りエラーハンドリングは 無視 省力です。
client.c
まずはクライアント側ですね。
socket() でソケットを作成した後に、connect() を使えばコネクションが張れるようです。
後は生成したソケットを使って、send() でサーバ側にデータを送るだけです。
送信するデータは fgets() で標準入力から取得します。
#include <stdio.h> #include <sys/socket.h> #include <arpa/inet.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(void){ int sockfd; char mes[64]; struct sockaddr_in server; server.sin_family = AF_INET; server.sin_port = htons(8888); server.sin_addr.s_addr = inet_addr("127.0.0.1"); sockfd = socket(AF_INET, SOCK_STREAM, 0); connect(sockfd, (struct sockaddr *)&server, sizeof(server)); printf("INPUT:"); fgets(mes, sizeof(mes), stdin); send(sockfd, mes, 64, 0); close(sockfd); return 0; }
接続先サーバの情報は sockaddr_in 構造体を使って socket に紐づけます。
※ sockaddr にキャストする必要アリです。
例では localhost の 8888 ポートに接続しています。
server.c
次はサーバ側ですね。
サーバは bind() を使って ソケットに IPアドレス/ポート番号を紐づけ、listen() で割り当てたポート番号に接続を作成できることをシステムに伝えます。
※ 例では最大5つの接続を受け持ちます。( 後段の処理が完了するまで最大5つまでの接続要求がキューに入ります )
実際のデータの送受信にはこのソケットは用いず、accept() を使ってデータ送受信用のソケットを生成して処理を委任します。
後は recv() を使ってデータを受信し、ファイルにデータを書き込み データ送受信用のソケットをクローズします。
※ 36行目には到達しないです。
#include <stdio.h> #include <sys/socket.h> #include <arpa/inet.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(void){ int sock, sockfd, sock_size; char mes[64]; struct sockaddr_in server; struct sockaddr_in client; FILE *file; server.sin_family = AF_INET; server.sin_port = htons(8888); server.sin_addr.s_addr = INADDR_ANY; sockfd = socket(AF_INET, SOCK_STREAM, 0); bind(sockfd, (struct sockaddr *)&server, sizeof(server)); listen(sockfd, 5); while(1){ sock_size = sizeof(client); sock = accept(sockfd, (struct sockaddr *)&client, &sock_size); recv(sock, mes, 64, 0); file = fopen("loger.txt", "a"); fprintf(file, mes); fclose(file); close(sock); } close(sockfd); return 0; }
クライアントと同じく、受け持つIPアドレス/ポート番号を sockaddr_in 構造体を使って socket に紐づけます。
こちらも sockaddr にキャストする必要アリです。
※ INADDR_ANY は全ての接続元( 0.0.0.0 )を表しています。
まとめると下記の形になりますね。
1.socket() を実行して TCPソケットを作成する。
2.bind() を実行してソケットにポート番号(IPアドレスも)を割り当てる。
3.listen() を実行し割り当てたポート番号へ接続を作成できることをシステムに伝える。
4.以下繰り返し
・接続要求を受け取るたびに、accept() を呼び出して新規ソケットを取得
・作成したソケットを介してクライアント(接続要求元)とやり取り
・close() でクライアントとの接続をクローズ