【msys2】Windowsネットワークプログラミング(winsock) ===================================== 「[[programing:linux-programing:network-programing:linux-socket-network-programing]]」記事で、Linux標準ソケットによる簡単なTCP通信のサンプルプログラムを動かした。このプログラムをWindows上でも動かせるようにしたので備忘録を残す。 msys2でのソケットライブラリー -------------------------- [[software/msys2/start]]でも `#include ` などのLinux標準ソケット関数がそのまま利用できれば良いのだが、どうも使えない模様。 そこで、`#include ` ヘッダーを指定しwinsock2ライブラリーを使う。winsock2ライブラリーは、Linux標準ソケット関数とかなり似ているが少し違う。 winsock2ライブラリーは32bit版だけのようで、msys2のMINGW32環境で32bitアプリとしてコンパイルを行う。Windowsの64bitパソコンでも、32bitアプリの実行は可能。 TCPソケット通信サンプルプログラム ----------------------------- 以下のサンプルプログラムでは、`WINSOCK_USE` の条件コンパイルで、Linux版と兼用できるソースにしている。 尚、システムコール時のエラー判定やタイムアウト監視など不十分なので、実際に使う場合はエラー処理などもよく吟味して利用する事。 ### 単純なTCPサーバ このサンプルは、接続してきたクライアントに対して「HELLO」という文字列を送信して終了。 #if defined(__MINGW64__) #error Cannot compile in MINGW64 environment, MINGW32 required. #elif defined(__MINGW32__) #define WINSOCK_USE 2.0 /* Only 32bit library */ #endif #include #include #include #include #ifdef WINSOCK_USE #include #else #include #include #include #endif int main(int argc, char *argv[]) { int n; struct sockaddr_in server; char buf[32]; #ifdef WINSOCK_USE SOCKET sock; WSADATA wsaData; // winsock2の初期化 WSAStartup(MAKEWORD(2,0), &wsaData); #else int sock; #endif /* ソケットの作成 */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); #ifdef WINSOCK_USE printf("error:%d\n",WSAGetLastError()); #endif } /* 接続先指定用構造体の準備 */ server.sin_family = AF_INET; server.sin_port = htons(12345); server.sin_addr.s_addr = inet_addr("127.0.0.1"); /* サーバに接続 */ connect(sock, (struct sockaddr *)&server, sizeof(server)); /* サーバからデータを受信 */ memset(buf, 0, sizeof(buf)); n = recv(sock, buf, sizeof(buf), 0); printf("%d, %s\n", n, buf); /* socketの終了 */ #ifdef WINSOCK_USE closesocket(sock); // winsock2の終了 WSACleanup(); #else close(sock); #endif return 0; } #### コンパイル方法 MINGW32シェルから下記コマンドを実行。 $ gcc -o tcp-test-server tcp-test-server.c ### 単純なTCPクライアント このサンプルは、サーバに接続すると文字列を受信して表示。 #if defined(__MINGW64__) #error Cannot compile in MINGW64 environment, MINGW32 required. #elif defined(__MINGW32__) #define WINSOCK_USE 2.0 /* Only 32bit library */ #endif #include #include //#include #include #ifdef WINSOCK_USE #include #else #include #include #include #endif int main(int argc, char *argv[]) { struct sockaddr_in addr; struct sockaddr_in client; #ifdef WINSOCK_USE int len; SOCKET sock0, sock; WSADATA wsaData; // winsock2の初期化 WSAStartup(MAKEWORD(2,0), &wsaData); #else socklen_t len; int sock0, sock; #endif printf("*** TCP test(server) program start ***\n"); usleep(500000); /* ソケットの作成 */ 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文字送信 */ send(sock, "HELLO", 5, 0); #ifdef WINSOCK_USE /* TCPセッションの終了 */ closesocket(sock); /* listen するsocketの終了 */ closesocket(sock0); // winsock2の終了 WSACleanup(); #else /* TCPセッションの終了 */ close(sock); /* listen するsocketの終了 */ close(sock0); #endif return 0; } #### コンパイル方法 MINGW32シェルから下記コマンドを実行。 $ gcc -o tcp-test-client tcp-test-client.c 補足 ---- * コンパイル時に、winsock2のライブラリー(`libws2_32.lib`)を明示的に`-lws2_32`指定しなくてもコンパイルエラーなく実行ファイルを生成した。 * MINGW64シェルの64bitコンパイル環境でも、`-lws2_32`を指定すればコンパイルは通ったが、実行時の挙動がどうも怪しかった。 関連記事 ------- * [[programing:linux-programing:network-programing:linux-socket-network-programing]] * [[software/msys2/msys2-ldd-dllcheck]] 参考 ---- 1. [[https://www.geekpage.jp/programming/winsock/|winsockプログラミング]] 2. [[https://qiita.com/UchiwaFuujinn/items/c376d8bfbbf0690ba13a?utm_source=pocket_mylist|Windows Console でUDPの送受信]] 3. [[https://hayabusa333.hatenadiary.org/entry/20110329/1301358227?utm_source=pocket_mylist|MinGWにてSocket通信を行うには]]