ソケットプログラミング
最近読んでるTCP/IPの本asin:4274065847の内容を試してみたいのと,
windowsでソフト作ってみたいのと,
二つの欲求からまずは簡単なものを作った.
サーバが5001/tcpで待ちうけて,クライアントとコネクション張れたら切断する,
というシンプルなもの.
文字を送るとかはまだ未実装.
サーバ側.
#include <stdio.h> //#include <WinSock.h> /* library: Wsock32.lib */ #include <winsock2.h> /* library: ws2_32.lib/上位互換性があるのでこっちを使う */ #include <stdlib.h> /* DEFAULT_PORT * 「Windows系OSのデフォルト設定ではエフェメラルポートは1024-5000」 * http://www.windows-world.jp/special/-/126591-3.html */ #define DEFAULT_PORT 5001 /* NBACKLOG * 保留中の接続のキューの最大値 * キューが小さいと,クライアントからの接続を拒否することになる * http://www.linux.or.jp/JM/html/LDP_man-pages/man2/listen.2.html */ #define NBACKLOG 5 /* * サーバ側の通信の手順 * socket() -> bind() -> listen() -> accept() -> closesocket() */ int main() { WSADATA wsaData; /* WinSockのバージョン情報を格納 * http://www.geocities.jp/playtown1056/program/ws_1.htm */ SOCKET sock; struct sockaddr_in addr; /* サーバのIPアドレスとポート番号を格納 */ int addr_len; /* addrのサイズ;accept()で使用 */ u_short port = DEFAULT_PORT; /* 自ホストの待ちうけポート */ int backlog = NBACKLOG; /* NBACKLOG(上記)を参照 */ /* WinSock2のDLL(ws2_32.lib)の初期化 */ WSAStartup(MAKEWORD(2, 0), &wsaData); /* MAKEWORD(a,b):要求するバージョンを * 記述するマクロ * a: メジャーバージョン * b: マイナーバージョン * e.g.) MAKEWORD(2.2): WinSock2.2を要求 */ /* ネットワークソケットの作成 */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { fprintf(stderr, "failed to socket()\n"); return EXIT_FAILURE; } /* 自分のアドレスの構造体を設定 */ memset(&addr, 0x0, sizeof(sockaddr_in)); addr.sin_family = AF_INET; /* UDP, TCP, etc. (WinSock.h) */ addr.sin_port = htons(port); /* ネットワークバイトに変換 */ // addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); addr.sin_addr.S_un.S_addr = htonl(INADDR_LOOPBACK); /* 自ホストのIPなのだからINADDR_LOOPBACKではダメなの? * http://www.linux.or.jp/JM/html/LDP_man-pages/man7/ip.7.html * http://eternalwindows.jp/network/winsock/winsock03s.html * ⇒ループバックでもできた. */ /* ソケットとsockaddr(IPアドレスとポート)の関連付け */ if (bind(sock, (sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) { fprintf(stderr, "failed to bind()\n"); return EXIT_FAILURE; } /* コネクション受付開始 */ if (listen(sock, backlog) == SOCKET_ERROR) { fprintf(stderr, "failed to listen()\n"); return EXIT_FAILURE; } /* コネクション受理 */ addr_len = sizeof(addr); if (accept(sock, (sockaddr *)&addr, &addr_len) == INVALID_SOCKET) { fprintf(stderr, "failed to accept()\n"); return EXIT_FAILURE; } /* コネクションを閉じる */ if (closesocket(sock) == SOCKET_ERROR) { fprintf(stderr, "failed to closesocket()\n"); return EXIT_FAILURE; } /* WinSockの終了処理 */ WSACleanup(); return EXIT_SUCCESS; } /* vim: set ts=4: */
クライアント側.
#include <stdio.h> #include <winsock2.h> #include <stdlib.h> /* DEFAULT_PORT * サーバ側で待ちうけポートを5001に決めたので,この番号. */ #define DEFAULT_PORT 5001 #define NBACKLOG 5 /* コマンドライン引数の順番 */ enum { CMD_NAME = 0, /* コマンドネーム */ DST_IP, /* サーバのIP */ // DST_PORT, /* ポートが指定できるようにしてもいいかもしれない */ }; /* * クライアント側の通信の手順 * socket() -> connect() -> closesocket() */ int main(int argc, char *argv[]) { WSADATA wsaData; SOCKET sock; struct sockaddr_in addr; /* サーバのIPアドレスとポート番号を格納 */ unsigned long dst_ip; /* サーバのIPアドレス(一時変数) */ u_short port = DEFAULT_PORT; /* サーバの待ちうけポート */ WSAStartup(MAKEWORD(2, 0), &wsaData); /* ドット表記のIPアドレスをバイナリに変換する */ if ((dst_ip = inet_addr(argv[DST_IP])) == INADDR_NONE) { fprintf(stderr, "invalid address: %s\n", argv[DST_IP]); return EXIT_FAILURE; } if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { fprintf(stderr, "failed to socket()\n"); return EXIT_FAILURE; } /* サーバのアドレスの構造体を設定 */ memset(&addr, 0x0, sizeof(sockaddr_in)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.S_un.S_addr = dst_ip; /* サーバに接続要求 */ if (connect(sock, (sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) { fprintf(stderr, "failed to bind()\n"); return EXIT_FAILURE; } /* コネクションを閉じる */ if (closesocket(sock) == SOCKET_ERROR) { fprintf(stderr, "failed to closesocket()\n"); return EXIT_FAILURE; } /* WinSockの終了処理 */ WSACleanup(); return EXIT_SUCCESS; } /* vim: set ts=4: */
参考
全体の概略と,細かい関数の動作も.WinSock version 1.1の話.
ソースはGUIを含めている.
http://yonex1.cis.ibaraki.ac.jp/~yonekura/2002kadai/lecture03.html
シンプルなソース.version 2.0
http://www.nhk.or.tv/kow/program/program_136.php
ちょっとGUIはいってきてる?ソース読みやすい. version2.2
http://eternalwindows.jp/network/winsock/winsock03s.html
perlだけど,大体同じ.
http://x68000.q-e-d.net/~68user/net/func.html
Windowsのエフェメラルポートって変わってるねって話.
http://www.windows-world.jp/special/-/126591-3.html
Programming UNIX Sockets in C - Frequently Asked Questions
http://www.kt.rim.or.jp/~ksk/sock-faq/unix-socket-faq-ja.html#toc4
ご存知JM.Linuxと大して変わらない.
http://www.linux.or.jp/JM/html/LDP_man-pages/man7/socket.7.html
http://www.asahi-net.or.jp/~NK2W-ISHR/winsock1.htm
http://www.geekpage.jp/programming/winsock/
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1322554618
http://wisdom.sakura.ne.jp/system/winapi/winsock/winSock2.html
http://www.geocities.jp/playtown1056/program/ws_1.htm