Linuxネットワークプログラミング(socket) ============================= 書籍「[[https://www.sbcr.jp/product/4797354522/|Linuxネットワークプログラミング]]」ソフトバンククリエイティブ(株)発行 の1~3章が参考になる。(下記リンク) 1. {{https://sbcr-dl-old.s3-ap-northeast-1.amazonaws.com/books/img/Linuxnet_01.pdf|インターネットの仕組み}} 2. {{https://sbcr-dl-old.s3-ap-northeast-1.amazonaws.com/books/img/Linuxnet_02.pdf|TCP通信の基礎}} 3. {{https://sbcr-dl-old.s3-ap-northeast-1.amazonaws.com/books/img/Linuxnet_03.pdf|UDP通信の基礎}} 4. {{https://sbcr-dl-old.s3-ap-northeast-1.amazonaws.com/books/img/Linuxnet_contents.pdf|目次}} 5. {{https://sbcr-dl-old.s3-ap-northeast-1.amazonaws.com/books/img/Linuxnet_hajime.pdf|はじめに}} UDPソケット通信サンプルプログラム ------------------------------ 以下のサンプルは、システムコール時のエラー判定やタイムアウト監視など不十分なので、実際に使う場合はエラー処理などもよく吟味して利用する事。 ### UDPパケットを受信待ちして返信 上記PDFのList3-17プログラムを参考。このサンプルは、受け取った相手に対してUDPでそのまま返信を繰り返すプログラム。 #include #include #include #include #include #include #include int main(int argc, char *argv[]) { int sock; struct sockaddr_in addr; struct sockaddr_in senderinfo; socklen_t addrlen; char buf[2048]; char senderstr[16]; int n; printf("*** UDP test(server) program start ***\n"); /* AF_INET+SOCK_DGRAMなので、IPv4のUDPソケット */ sock = socket(AF_INET, SOCK_DGRAM, 0); /* 待ち受けポート番号を12345にするためにbind()を行う */ addr.sin_family = AF_INET; addr.sin_port = htons(12345); addr.sin_addr.s_addr = INADDR_ANY; bind(sock, (struct sockaddr *)&addr, sizeof(addr)); while (1) { memset(buf, 0, sizeof(buf)); /* recvfrom()を利用してUDPソケットからデータを受信 */ addrlen = sizeof(senderinfo); n = recvfrom(sock, buf, sizeof(buf) - 1, 0, (struct sockaddr *)&senderinfo, &addrlen); /* 送信元に関する情報を表示 */ #if 1 inet_ntop(AF_INET, &senderinfo.sin_addr, senderstr, sizeof(senderstr)); #else strcpy(senderstr, inet_ntoa(senderinfo.sin_addr)); #endif printf("recvfrom : %s, port=%d\n", senderstr, ntohs(senderinfo.sin_port)); /* UDPで返信 */ sendto(sock, buf, n, 0, (struct sockaddr *)&senderinfo, addrlen); /* 送信元に関する情報をもう一度表示 */ printf("sent data to : %s, port=%d\n", senderstr, ntohs(senderinfo.sin_port)); } /* このサンプルコードはここへは到達しません */ close(sock); return 0; } ### UDPパケットの送信&受信 上記PDFのList3-18プログラムを参考。上記のUDPアプリケーションに対してUDPパケットを送信して返信を受け取るプログラム。例えば、「./udp-test-client 127.0.0.1」のように宛先を指定して実行する。 #include #include #include #include #include #include #include void print_my_port_num(int sock) { struct sockaddr_in s; socklen_t sz = sizeof(s); getsockname(sock, (struct sockaddr *)&s, &sz); printf("%d\n", ntohs(s.sin_port)); } int main(int argc, char *argv[]) { int sock; struct sockaddr_in addr; struct sockaddr_in senderinfo; socklen_t senderinfolen; int n; char buf[2048]; if (argc != 2) { fprintf(stderr, "Usage : %s dstipaddr\n", argv[0]); return 1; } sock = socket(AF_INET, SOCK_DGRAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(12345); #if 1 inet_pton(AF_INET, argv[1], &addr.sin_addr.s_addr); #else inet_aton(argv[1], &addr.sin_addr); #endif n = sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr)); if (n < 1) { perror("sendto"); return 1; } print_my_port_num(sock); memset(buf, 0, sizeof(buf)); senderinfolen = sizeof(senderinfo); recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&senderinfo, &senderinfolen); printf("%s\n", buf); close(sock); return 0; } TCPソケット通信サンプルプログラム ----------------------------- 以下のサンプルは、システムコール時のエラー判定やタイムアウト監視など不十分なので、実際に使う場合はエラー処理などもよく吟味して利用する事。 ### 単純なTCPサーバ 上記PDFのList2-5プログラムを参考。このサンプルは、接続してきたクライアントに対して「HELLO」という文字列を送信して終了。 #include #include //#include #include #include #include #include int main(int argc, char *argv[]) { int sock0; struct sockaddr_in addr; struct sockaddr_in client; socklen_t len; int sock; printf("*** TCP test(server) program start ***\n"); /* ソケットの作成 */ sock0 = socket(AF_INET, SOCK_STREAM, 0); /* ソケットの設定 */ addr.sin_family = AF_INET; addr.sin_port = htons(12345); addr.sin_addr.s_addr = INADDR_ANY; bind(sock0, (struct sockaddr *)&addr, sizeof(addr)); /* TCPクライアントからの接続要求を待てる状態にする */ listen(sock0, 5); /* TCPクライアントからの接続要求を受け付ける */ len = sizeof(client); sock = accept(sock0, (struct sockaddr *)&client, &len); /* 5文字送信 */ write(sock, "HELLO", 5); /* TCPセッションの終了 */ close(sock); /* listen するsocketの終了 */ close(sock0); return 0; } ### 単純なTCPクライアント 上記PDFのList2-6プログラムを参考。このサンプルは、サーバに接続すると文字列を受信して表示。 #include #include #include #include #include #include #include int main(int argc, char *argv[]) { struct sockaddr_in server; int sock; char buf[32]; int n; /* ソケットの作成 */ sock = socket(AF_INET, SOCK_STREAM, 0); /* 接続先指定用構造体の準備 */ server.sin_family = AF_INET; server.sin_port = htons(12345); /* 127.0.0.1はlocalhost */ #if 1 inet_pton(AF_INET, "127.0.0.1", &server.sin_addr.s_addr); #else inet_aton("127.0.0.1", &server.sin_addr); #endif /* サーバに接続 */ connect(sock, (struct sockaddr *)&server, sizeof(server)); /* サーバからデータを受信 */ memset(buf, 0, sizeof(buf)); n = read(sock, buf, sizeof(buf)); printf("%d, %s\n", n, buf); /* socketの終了 */ close(sock); return 0; } 関連記事 ------- * [[programing:linux-programing:network-programing:msys2-winsock-network-programing]] * [[software:wireshark:start]] 参考書籍 -------- 1. [[http://www.sbcr.jp/products/4797354522.html|Linuxネットワークプログラミング(SBクリエイティブ)]] 2. [[https://www.ohmsha.co.jp/book/9784274065194/|TCP/IPソケットプログラミング C言語編(オーム社)]] 3. [[http://www.sbcr.jp/products/4797386479.html|ふつうのLinuxプログラミング 第2版]] 4. [[http://www.ncad.co.jp/~mtaneda/lnpb/|Linuxネットワークプログラミングバイブル(秀和システム)]] 上記[4.]の、小俣氏と種田氏が書かれた本が、実践的でとても参考になる。残念ながら冊子版は絶版になっているようだが、Amazoneから電子書籍は購入可能。尚、上リンクから、誌面のサンプルソースもダウンロードできる。 参考 ---- 1. [[http://www-cms.phys.s.u-tokyo.ac.jp/~naoki/CIPINTRO/NETWORK/struct.html|UNIXネットワークプログラミングに登場する構造体の紹介と正しい使い方]] 2. [[https://qiita.com/tajima_taso/items/fdfed88c1e735ffb41e8|C言語で学ぶソケットAPI入門 第4回 UDPサーバ/クライアント編 #1]] 3. [[http://www.geekpage.jp/programming/linux-network/udp.php|UDPを使う]] 4. [[https://docs.oracle.com/cd/E19455-01/806-2730/6jbu725ke/index.html|第 2 章 ソケットインタフェース]] -----