記述例およびサンプルに含まれるファイルの全部、または一部を使用したことによる損害等について、一切の責任を負いません。また、サンプルの文字コードはS-JISで提供しますので、ご使用の際はWindowsからFTPするなどして適切な文字コードに変換してください。尚、サンプル中には説明の簡略化のため意味のないコードや、実用上問題のあるコードも含まれていますのでご注意ください。
今までスレッドを使用したことがない方は、スレッドと聞くだけで躊躇されるかもしれないが、実際にやってみればそれほど難しいものではない。スレッドに関しては別にページを用意しているのでそちらも参照して欲しい。
<受信スレッドの生成>
/* 受信スレッド生成 */ pthread_create(&tid,NULL,waitReceiveThread,NULL); pthread_join(tid,NULL); /* 受信スレッド終了待ち */<受信スレッドルーチン>
void* waitReceiveThread(void* pParam) { char buf[1024]; int recvSize; while(1) { /* データ受信待ち */ recvSize = recv(fd,buf,1024,0); printf("Received %d bytes\n",recvSize); if(recvSize == 0) /* 相手CLOSE? */ { printf("check\n"); close(fd); break; } } return NULL; }受信スレッドルーチンは単にrecvのループになっている。recvはデータを受信するまで戻ってこないのでCPU時間は消費しない。SOCKETがクローズされるとrecvは戻り値=0で戻ってくるので、その場合にはループをbreakする処理を入れている。受信スレッドの生成元スレッドはpthread_joinで新たに生成したスレッドの終了を待機しているので、受信スレッドルーチンが終了すれば生成元スレッドも終了する。
int waitReceive(void) { fd_set fds; char buf[1024]; int recvSize; /* バッチ共通初期処理 */ while(1) /* メッセージループ */ { FD_ZERO(&fds); /* fd_set初期化 */ FD_SET(fd,&fds); /* fd設定 */ select(fd + 1,&fds,NULL,NULL,NULL); /* データ受信待ち */ if(FD_ISSET(fd,&fds)) /* 該当fd読み込みデータあり? */ { /* データ受信 */ recvSize = recv(fd,buf,1024,0); printf("Received %d bytes\n",recvSize); if(recvSize == 0) /* 相手CLOSE? */ { printf("check\n"); close(fd); break; } } } return 0; }
<受信スレッドの生成>
/* 受信スレッド生成 */ hThread = (HANDLE)_beginthreadex(NULL,0,waitReceiveThread,NULL,0,&threadId); WaitForSingleObject(hThread,INFINITE); /* 受信スレッド終了待ち */ CloseHandle(hThread); /* ハンドルクローズ */<受信スレッドルーチン>
DWORD WINAPI waitReceiveThread(LPVOID pParam) { char buf[1024]; int recvSize; while(1) { /* データ受信待ち */ recvSize = recv(fd,buf,1024,0); printf("Received %d bytes\n",recvSize); if(recvSize == 0) /* 相手CLOSE? */ { printf("check\n"); closesocket(fd); /* CLOSE */ break; } } return 0; }この例でも受信スレッドルーチンの生成元スレッドは、pthreadのときと同様に新たに生成したスレッドの終了を待機している。Win32ではスレッドのハンドルがシグナル状態になるのをWaitForSingleObjectで待機する。受信スレッドルーチンが終了すれば生成元スレッドも終了する。
スレッドrecvのサンプル(ソースはLinuxでもコンパイルできるようになっている。UNIXとWindowsの違いを見てみて欲しい。)
[Winsock]selectを使う
selectを使う場合はUNIXのSOCKETとまったく同じだ。よりWindowsっぽく書くなら、WSAAsyncSelectを使うという手があるが、こちらはメッセージを使用する。メッセージを使用するにはウィンドウが必要になる僕はメッセージの仕組みをあまり詳しくないので専らイベントを使用する。
[Winsock]イベントを使う
Winsock2.0ではWin32のイベントオブジェクトを使用することができる。メッセージを利用しないのでウィンドウが必要なく、GUIがないプログラムで使いやすい。Anpsockもこの方式を使っている。ところが、イベントを使ったWinsockの解説書はあまりない。そもそも、Winsock2.0の解説書が少ない。
イベントに関しては別にページを用意しているのでそちらも参照して欲しい。
int waitReceive(void) { char buf[1024]; int recvSize; int nRet; HANDLE hEvent = WSACreateEvent(); WSANETWORKEVENTS events; WSAEventSelect(fd,hEvent,FD_READ|FD_CLOSE); while(1) { /* イベント待ち */ nRet = WSAWaitForMultipleEvents(1,&hEvent,FALSE,WSA_INFINITE,FALSE); if(nRet == WSA_WAIT_FAILED) { printf("!!!!!!!!!!!!!!!!!!!!1\n"); break; } /* イベントの調査 */ if(WSAEnumNetworkEvents(fd,hEvent,&events) == SOCKET_ERROR) { printf("???\n"); } else { /* CLOSE */ if(events.lNetworkEvents & FD_CLOSE) { printf("close\n"); closesocket(fd); break; } /* READ */ if(events.lNetworkEvents & FD_READ) { recvSize = recv(fd,buf,1024,0); printf("Received %d bytes\n",recvSize); } } } WSACloseEvent(hEvent); /* イベントクローズ */ return 0; }
イベントrecvのサンプル
[Java]Socket(クライアント)
Javaでクライアントのソケットを作成するにはホストとポートを指定してSocketをnewするだけである。たったのこれだけでCで言うところのsocketからconnectの呼び出しまで済んでしまうから驚きである。
// クライアントソケット作成 Socket conn = new Socket("localhost",port); System.out.println("Connecting to port " + port); // データ受信スレッド生成 RecvData rd = new RecvData(conn.getInputStream()); rd.start();データの受信は他の言語と同様スレッドを用いている。実際にサンプルを見ていただければお分かりになると思うが、わずか5、60行でクライアントのプログラムが書けるのである。素晴らしい!
class RecvData extends Thread { InputStream st; public RecvData(InputStream st) { this.st = st; } public void run() { int data; try { // データ読み込み while((data = st.read()) != -1) { System.out.print((char)data); } } catch(IOException e) { System.out.println(e); } } }
// サーバーソケット作成 ServerSocket server = new ServerSocket(port); System.out.println("Listening on port " + port);作成したサーバーソケットがAcceptするとクライアントの項で既出のSocketを返すので、以降同様に処理してやれば良い。サンプルでは受信スレッドのクラスはクライアントと共有している。
// Accept Socket conn = server.accept(); System.out.println("Accept"); // データ受信スレッド生成 RecvData rd = new RecvData(conn.getInputStream()); rd.start();
Copyright(C) 2001-2003 Allergy Design Office All rights reserved.
[Home]