C言語でソケット通信によるネットワークプログラミングを教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
C言語のINETドメイン/UNIXドメインソケット通信によるネットワークプログラミング
本記事では,C言語のINETドメイン/UNIXドメインソケット通信によるネットワークプログラミングを紹介します.
ネットワークプログラミングには,インターネットに接続できるINETドメインソケット通信,高いスループットを持つUNIXドメインソケット通信があります.
INETドメイン,UNIXドメインソケット通信の両方で,TCP(コネクション指向),UDP(コネクションレス)のコードを解説します.
本記事を読むと,C言語のネットワークプログラミングの基礎がわかります.
TCPとUDPを知りたいあなたはこちらの動画がおすすめです!
ネットワークプログラミングでは,クライアントとサーバの2種類のプログラムを実行します.
クライアントはサーバに文字列"Hello World"を送信し,サーバで"Hello World"を表示して終了します.
1 |
int socket(int domain, int type, int protocol); |
ソケット通信はsocket関数を呼び出すことから処理が始まります.
他にも上記のsocket関数のリンクの関連項目にある様々な関数を呼び出すので難しく感じるかもしれませんが,慣れるまでの辛抱ですので最後まで読みましょう!
INETドメインソケット通信
C言語のINETドメインソケット通信によるネットワークプログラミングを紹介します.
TCPクライアント/サーバ,UDPクライアント・サーバのコードを解説します.
INETドメインソケット通信のTCPクライアント/サーバ
INETドメインソケット通信のTCPクライアント/サーバのコード一式(Makefileを含む)はこちらからダウンロードできます.
TCPクライアントのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT_NUM 65432 #define HOSTNAME "127.0.0.1" #define SEND_DATA "Hello World" int main(void) { struct sockaddr_in server_addr; int sock; int n; memset(&server_addr, 0, sizeof(struct sockaddr_in)); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return 1; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT_NUM); server_addr.sin_addr.s_addr = inet_addr(HOSTNAME); if (connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) { perror("connect"); goto end_socket; } if ((n = send(sock, SEND_DATA, sizeof(SEND_DATA), 0)) < 0) { perror("send"); goto end_socket; } if (n == sizeof(SEND_DATA)) { printf("Sending data is successful.\n"); } else { printf("Sending data is not successful.\n"); } end_socket: if (close(sock) < 0) { perror("close"); return 2; } return 0; } |
TCPサーバのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define BUFSIZE 1024 #define PORT_NUM 65432 #define BACKLOG 1024 int main(void) { int server_sock; struct sockaddr_in server_sockaddr; struct sockaddr_in client_sockaddr; char buf[BUFSIZE]; socklen_t len; int client_sock; int n; memset(&server_sockaddr, 0, sizeof(struct sockaddr_in)); memset(&client_sockaddr, 0, sizeof(struct sockaddr_in)); memset(buf, 0, sizeof(buf)); if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return 1; } server_sockaddr.sin_family = AF_INET; server_sockaddr.sin_port = htons(PORT_NUM); server_sockaddr.sin_addr.s_addr = INADDR_ANY; if ((bind(server_sock, (struct sockaddr *) &server_sockaddr, sizeof(server_sockaddr))) < 0) { perror("bind"); goto end_server_socket; } if (listen(server_sock, BACKLOG) < 0) { perror("listen"); goto end_server_socket; } len = sizeof(client_sockaddr); if ((client_sock = accept(server_sock, (struct sockaddr *) &client_sockaddr, &len)) < 0) { perror("accept"); goto end_server_socket; } if ((n = recv(client_sock, buf, sizeof(buf), 0)) < 0) { perror("recv"); goto end_client_socket; } printf("%s\n", buf); end_client_socket: if (close(client_sock) < 0) { perror("close"); if (close(server_sock) < 0) { return 2; } else { return 3; } } end_server_socket: if (close(server_sock) < 0) { perror("close"); return 4; } return 0; } |
実行方法は以下になります.
まず,ダウンロードしたzipファイルを解凍,作成したディレクトリに移動,makeコマンドでビルドしてクライアントとサーバの実行ファイルの作成を行います.
1 2 3 4 5 |
$ unzip inet_tcp.zip $ cd inet_tcp $ make gcc -o inet_tcp_client inet_tcp_client.c -Wall gcc -o inet_tcp_server inet_tcp_server.c -Wall |
次に,サーバを実行します.
実行中となり,クライアントからのリクエストを受け付けている状態になります.
1 |
$ inet_tcp_server |
別の端末でクライアントを実行します.
「Sending data is successful.」と表示されます.
1 2 |
$ inet_tcp_client Sending data is successful. |
再度サーバの実行端末を見ると,「Hello World」と表示されていることがわかります.
他のクライアント/サーバも同様に実行できます.
1 2 |
$ inet_tcp_server Hello World |
INETドメインソケット通信のUDPクライアント/サーバ
INETドメインソケット通信のUDPクライアント/サーバのコード一式(Makefileを含む)はこちらからダウンロードできます.
UDPクライアントのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT_NUM 65432 #define HOSTNAME "127.0.0.1" #define SEND_DATA "Hello World" int main(void) { int sock; struct sockaddr_in addr; int n; memset(&addr, 0, sizeof(struct sockaddr_in)); if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return 1; } addr.sin_family = AF_INET; addr.sin_port = htons(PORT_NUM); addr.sin_addr.s_addr = inet_addr(HOSTNAME); if ((n = sendto(sock, SEND_DATA, sizeof(SEND_DATA), 0, (struct sockaddr *) &addr, sizeof(addr))) < 0) { perror("sendto"); goto end_socket; } if (n == sizeof(SEND_DATA)) { printf("Sending data is successful.\n"); } else { printf("Sending data is not successful.\n"); } end_socket: if (close(sock) < 0) { perror("close"); return 2; } return 0; } |
UDPサーバのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define PORT_NUM 65432 #define BUFSIZE 1024 int main(void) { int sock; struct sockaddr_in addr; char buf[BUFSIZE]; memset(&addr, 0, sizeof(struct sockaddr_in)); memset(buf, 0, sizeof(buf)); if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); return 1; } addr.sin_family = AF_INET; addr.sin_port = htons(PORT_NUM); addr.sin_addr.s_addr = INADDR_ANY; if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("bind"); goto end_socket; } if (recv(sock, buf, sizeof(buf), 0) < 0) { perror("recv"); goto end_socket; } printf("%s\n", buf); end_socket: if (close(sock) < 0) { perror("close"); return 2; } return 0; } |
実行方法は以下になります.
1 2 3 4 5 |
$ unzip inet_udp.zip $ cd inet_udp $ make gcc -o inet_udp_client inet_udp_client.c -Wall gcc -o inet_udp_server inet_udp_server.c -Wall |
次に,サーバを実行します.
1 |
$ inet_udp_server |
別の端末でクライアントを実行します.
「Sending data is successful.」と表示されます.
1 2 |
$ inet_udp_client Sending data is successful. |
再度サーバの実行端末を見ると,「Hello World」と表示されていることがわかります.
1 2 |
$ inet_udp_server Hello World |
UNIXドメインソケット通信
C言語のINETドメインソケット通信によるネットワークプログラミングを紹介します.
TCPクライアント/サーバ,UDPクライアント・サーバのコードを解説します.
UNIXドメインソケット通信のTCPクライアント/サーバ
UNIXドメインソケット通信のTCPクライアント/サーバのコード一式(Makefileを含む)はこちらからダウンロードできます.
TCPクライアントのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define SERVER_PATH "/tmp/unix_sock.server" #define CLIENT_PATH "/tmp/unix_sock.client" #define SEND_DATA "Hello World" #define BUFSIZE 1024 int main(void) { int client_sock, len, n; struct sockaddr_un server_sockaddr; struct sockaddr_un client_sockaddr; memset(&server_sockaddr, 0, sizeof(struct sockaddr_un)); memset(&client_sockaddr, 0, sizeof(struct sockaddr_un)); if ((client_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("socket"); return 1; } client_sockaddr.sun_family = AF_UNIX; strcpy(client_sockaddr.sun_path, CLIENT_PATH); len = sizeof(client_sockaddr); unlink(CLIENT_PATH); if (bind(client_sock, (struct sockaddr *) &client_sockaddr, len) < 0) { perror("socket"); goto end_socket; } server_sockaddr.sun_family = AF_UNIX; strcpy(server_sockaddr.sun_path, SERVER_PATH); if (connect(client_sock, (struct sockaddr *) &server_sockaddr, len) < 0) { perror("connect"); goto end_socket; } if ((n = send(client_sock, SEND_DATA, sizeof(SEND_DATA), 0)) < 0) { perror("send"); goto end_socket; } if (n == sizeof(SEND_DATA)) { printf("Sending data is successful.\n"); } else { printf("Sending data is not successful.\n"); } end_socket: if (close(client_sock) < 0) { perror("close"); return 2; } return 0; } |
TCPサーバのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define SOCK_PATH "/tmp/unix_sock.server" #define BUFSIZE 1024 #define BACKLOG 1024 int main(void) { int server_sock, client_sock; socklen_t len; int n = 0; struct sockaddr_un server_addr; struct sockaddr_un client_addr; char buf[BUFSIZE]; memset(&server_addr, 0, sizeof(struct sockaddr_un)); memset(&client_addr, 0, sizeof(struct sockaddr_un)); memset(buf, 0, BUFSIZE); if ((server_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("socket"); return 1; } server_addr.sun_family = AF_UNIX; strcpy(server_addr.sun_path, SOCK_PATH); len = sizeof(server_addr); unlink(SOCK_PATH); if (bind(server_sock, (struct sockaddr *) &server_addr, len) < 0) { perror("bind"); goto end_server_socket; } if (listen(server_sock, BACKLOG) < 0) { perror("listen"); goto end_server_socket; } if ((client_sock = accept(server_sock, (struct sockaddr *) &client_addr, &len)) < 0) { perror("accept"); goto end_server_socket; } len = sizeof(client_addr); if (getpeername(client_sock, (struct sockaddr *) &client_addr, &len) < 0) { perror("getpeername"); goto end_client_socket; } if ((n = recv(client_sock, buf, sizeof(buf), 0)) < 0) { perror("recv"); goto end_client_socket; } printf("%s\n", buf); end_client_socket: if (close(client_sock) < 0) { perror("close"); if (close(server_sock) < 0) { return 2; } else { return 3; } } end_server_socket: if (close(server_sock) < 0) { perror("close"); return 4; } return 0; } |
実行方法は以下になります.
1 2 3 4 5 |
$ unzip unix_tcp.zip $ cd unix_tcp $ make gcc -o unix_tcp_client unix_tcp_client.c -Wall gcc -o unix_tcp_server unix_tcp_server.c -Wall |
次に,サーバを実行します.
1 |
$ unix_tcp_server |
別の端末でクライアントを実行します.
「Sending data is successful.」と表示されます.
1 2 |
$ unix_tcp_client Sending data is successful. |
再度サーバの実行端末を見ると,「Hello World」と表示されていることがわかります.
1 2 |
$ unix_tcp_server Hello World |
UNIXドメインソケット通信のUDPクライアント/サーバ
UNIXドメインソケット通信のUDPクライアント/サーバのコード一式(Makefileを含む)はこちらからダウンロードできます.
UDPクライアントのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define SERVER_PATH "/tmp/unix_sock.server" #define SEND_DATA "Hello World" int main(void) { int client_sock, n; struct sockaddr_un addr; memset(&addr, 0, sizeof(struct sockaddr_un)); if ((client_sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { perror("socket"); return 1; } addr.sun_family = AF_UNIX; strcpy(addr.sun_path, SERVER_PATH); if ((n = sendto(client_sock, SEND_DATA, sizeof(SEND_DATA), 0, (struct sockaddr *) &addr, sizeof(addr))) < 0) { perror("sendto"); goto end_socket; } if (n == sizeof(SEND_DATA)) { printf("Sending data is successful.\n"); } else { printf("Sending data is not successful.\n"); } end_socket: if (close(client_sock) < 0) { perror("close"); return 2; } return 0; } |
UDPサーバのコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define SOCK_PATH "/tmp/unix_sock.server" #define BUFSIZE 1024 int main(void) { int server_sock; socklen_t len; struct sockaddr_un server_addr, peer_addr; char buf[BUFSIZE]; memset(buf, 0, BUFSIZE); if ((server_sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { perror("socket"); return 1; } memset(&server_addr, 0, sizeof(struct sockaddr_un)); server_addr.sun_family = AF_UNIX; strcpy(server_addr.sun_path, SOCK_PATH); len = sizeof(server_addr); unlink(SOCK_PATH); if (bind(server_sock, (struct sockaddr *) &server_addr, len) < 0) { perror("bind"); goto end_server_socket; } if (recvfrom(server_sock, buf, BUFSIZE, 0, (struct sockaddr *) &peer_addr, &len) < 0) { perror("recvfrom"); goto end_server_socket; } printf("%s\n", buf); end_server_socket: if (close(server_sock) < 0) { perror("close"); return 2; } return 0; } |
実行方法は以下になります.
1 2 3 4 5 |
$ unzip unix_udp.zip $ cd unix_udp $ make gcc -o unix_udp_client unix_udp_client.c -Wall gcc -o unix_udp_server unix_udp_server.c -Wall |
次に,サーバを実行します.
1 |
$ unix_udp_server |
別の端末でクライアントを実行します.
「Sending data is successful.」と表示されます.
1 2 |
$ unix_udp_client Sending data is successful. |
再度サーバの実行端末を見ると,「Hello World」と表示されていることがわかります.
1 2 |
$ unix_udp_server Hello World |
まとめ
C言語でINETドメイン/UNIXドメインソケット通信によるネットワークプログラミングを紹介しました.
ネットワークプログラミングのTCP/UDPクライアント/サーバのプログラムを実行したり,コードを修正したりして理解を深めましょう!
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!