Microsoft Visual C++ 2010 Express |
■UDPプロトコルでクライアント/サーバー通信 | Prev Top Next |
関連ページ:なし |
ではソースを見ていきますが、最初にいくつか注意点。 前回の記事と同じことを書きますが、ネットワーク系のサンプルソースはマルチバイト文字セットを使用します。 ですのでプロジェクトのプロパティの文字セットを変更してください。
次にこのページのサンプルではサーバー側のプログラムに 50000番 のポート番号を割り当てています。 実行中の他のプログラムが使用中の場合は 50000番 をあけるか、またはプログラムを修正して未使用の別のポート番号を割り当ててください。
#include <stdio.h> #include <WINSOCK2.h> #pragma comment( lib, "WS2_32.lib" ) // アプリケーションが要求するバージョン #define MAJOR_VERSION 2 #define MINOR_VERSION 0 // ポート番号 #define PORT 50000 // データ量の最大値は SO_MAX_MSG_SIZE #define MESSAGE_SIZE 1024 int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmpLine*/, INT /*nCmdShow*/ ) { int hr = -1; // WSAStartup() の呼び出し回数 int WSAStartupCount = 0; // ソケット識別子 SOCKET SocketID = INVALID_SOCKET; // 送受信バッファ char SendBuffer[MESSAGE_SIZE], RecvBuffer[MESSAGE_SIZE]; // デバッガ出力用バッファ TCHAR OutString[512]; // WS2_32.dllの初期化 { WSADATA wsd; // WS2_32.dllの初期化 hr = WSAStartup( MAKEWORD( MAJOR_VERSION, MINOR_VERSION ), &wsd ); if( hr != 0 ) { sprintf_s( OutString, "WSAStartup()でエラー [ ErrorCode:%d ]\n", hr ); OutputDebugString( OutString ); hr = -1; goto EXIT; } WSAStartupCount++; // WSADATA::wVersion には、WSAStartup() に指定したバージョン以下でライブラリがサポートする最大バージョンが格納される // ここでは完全に一致する場合のみ動作するようにする if( LOBYTE( wsd.wVersion ) != MAJOR_VERSION || HIBYTE( wsd.wVersion ) != MINOR_VERSION ) { sprintf_s( OutString, "ライブラリがサポートするバージョンは[ %d.%d ]ですがアプリが要求するバージョンは[ %d.%d ]です\n", LOBYTE( wsd.wVersion ), HIBYTE( wsd.wVersion ), MAJOR_VERSION, MINOR_VERSION ); OutputDebugString( OutString ); hr = -1; goto EXIT; } } // ソケットの作成 { SOCKADDR_IN SocketAddr; // ソケットの作成 SocketID = WSASocket( AF_INET, SOCK_DGRAM, // 非接続型ソケット IPPROTO_UDP, // UDPプロトコルを指定する NULL, 0, 0 ); if( SocketID == INVALID_SOCKET ) { sprintf_s( OutString, "WSASocket()でエラー [ ErrorCode:%d ]\n", WSAGetLastError() ); OutputDebugString( OutString ); hr = -1; goto EXIT; } ::ZeroMemory( &SocketAddr, sizeof(SOCKADDR_IN) ); SocketAddr.sin_family = AF_INET; SocketAddr.sin_addr.s_addr = htonl(INADDR_ANY); SocketAddr.sin_port = htons( PORT ); // すべてのIPアドレスとポート番号を関連付ける hr = bind( SocketID, (SOCKADDR*)&SocketAddr, sizeof(SocketAddr) ); if( hr != 0 ) { sprintf_s( OutString, "bind()でエラー [ ErrorCode:%d ]\n", WSAGetLastError() ); OutputDebugString( OutString ); hr = -1; goto EXIT; } } OutputDebugString( "UDP通信開始!!\n" ); while( true ) { RecvBuffer[0] = '\0'; SendBuffer[0] = '\0'; SOCKADDR_IN SockAddr; int AddrSize = sizeof(SockAddr); // クライアントから受信 { WSABUF buf; buf.buf = RecvBuffer; buf.len = MESSAGE_SIZE; DWORD RecvBytes = 0; // データグラムを受信して送信元のアドレスを保存する hr = WSARecvFrom( SocketID, &buf, 1, &RecvBytes, 0, (SOCKADDR*)&SockAddr, // 送信元情報 &AddrSize, NULL, NULL ); if( hr != 0 ) { sprintf_s( OutString, "WSARecvFrom()でエラー [ ErrorCode:%d ]\n", WSAGetLastError() ); OutputDebugString( OutString ); hr = -1; goto EXIT; } } // クライアントへ送信 { sprintf_s( SendBuffer, "-%s", RecvBuffer ); WSABUF buf; buf.buf = SendBuffer; buf.len = MESSAGE_SIZE; DWORD SendBytes = 0; // データグラムを送信する hr = WSASendTo( SocketID, &buf, 1, &SendBytes, 0, (SOCKADDR*)&SockAddr, // 送信元情報 AddrSize, NULL, NULL ); if( hr != 0 ) { sprintf_s( OutString, "WSASendTo()でエラー [ ErrorCode:%d ]\n", WSAGetLastError() ); OutputDebugString( OutString ); hr = -1; goto EXIT; } } SYSTEMTIME st; ::GetLocalTime( &st ); sprintf_s( OutString, "%d:%d:%d:%d [ 受信:%s ][ 送信:%s ]\n", st.wHour, st.wSecond, st.wMinute, st.wMilliseconds, RecvBuffer, SendBuffer ); OutputDebugString( OutString ); } hr = 0; EXIT: // ソケットの切断 if( SocketID != INVALID_SOCKET ) { if( closesocket( SocketID ) != 0 ) { sprintf_s( OutString, "closesocket()でエラー [ ErrorCode:%d ]\n", WSAGetLastError() ); OutputDebugString( OutString ); } } // WS2_32.dllの開放 for( int i=0; i<WSAStartupCount; i++ ) { if( WSACleanup() != 0 ) { sprintf_s( OutString, "WSACleanup()でエラー [ ErrorCode:%d ]\n", WSAGetLastError() ); OutputDebugString( OutString ); } } return hr; }---main.cpp ( クライアント側 )---
#include <stdio.h> #include <WINSOCK2.h> #pragma comment( lib, "WS2_32.lib" ) // アプリケーションが要求するバージョン #define MAJOR_VERSION 2 #define MINOR_VERSION 0 // 接続先のサーバーのIPアドレス。127.0.0.1は特殊なアドレスで自分自身を示す。 // サンプルでは1台のPC上でテストしたため、このIPアドレスを指定する。 #define IP "127.0.0.1" // ポート番号 #define PORT 50000 // データ量の最大値は SO_MAX_MSG_SIZE #define MESSAGE_SIZE 1024 int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmpLine*/, INT /*nCmdShow*/ ) { int hr = -1; // WSAStartup() の呼び出し回数 int WSAStartupCount = 0; // ソケット識別子 SOCKET SocketID = INVALID_SOCKET; // 送受信バッファ char SendBuffer[MESSAGE_SIZE], RecvBuffer[MESSAGE_SIZE]; // デバッガ出力用バッファ TCHAR OutString[512]; // WS2_32.dllの初期化 { // WSADATA 構造体 WSADATA wsd; // WS2_32.dllの初期化 hr = WSAStartup( MAKEWORD( MAJOR_VERSION, MINOR_VERSION ), &wsd ); if( hr != 0 ) { sprintf_s( OutString, "WSAStartup()でエラー [ ErrorCode:%d ]\n", hr ); OutputDebugString( OutString ); hr = -1; goto EXIT; } WSAStartupCount++; // WSADATA::wVersion には、WSAStartup() に指定したバージョン以下でライブラリがサポートする最大バージョンが格納される // ここでは完全に一致する場合のみ動作するようにする if( LOBYTE( wsd.wVersion ) != MAJOR_VERSION || HIBYTE( wsd.wVersion ) != MINOR_VERSION ) { sprintf_s( OutString, "ライブラリがサポートするバージョンは[ %d.%d ]ですがアプリが要求するバージョンは[ %d.%d ]です\n", LOBYTE( wsd.wVersion ), HIBYTE( wsd.wVersion ), MAJOR_VERSION, MINOR_VERSION ); OutputDebugString( OutString ); hr = -1; goto EXIT; } } // ソケットの作成 { // ソケットの作成 SocketID = WSASocket( AF_INET, SOCK_DGRAM, // 非接続型ソケット IPPROTO_UDP, // UDPプロトコルを指定する NULL, 0, 0 ); if( SocketID == INVALID_SOCKET ) { sprintf_s( OutString, "WSASocket()でエラー [ ErrorCode:%d ]\n", WSAGetLastError() ); OutputDebugString( OutString ); hr = -1; goto EXIT; } } OutputDebugString( "UDP通信開始!!\n" ); while( true ) { RecvBuffer[0] = '\0'; SendBuffer[0] = '\0'; SOCKADDR_IN SockAddr; int AddrSize = sizeof(SockAddr); // サーバーへ送信 { // 送信データを作成 static DWORD data = 0; sprintf_s( SendBuffer, "%d", data ); data ++; WSABUF buf; buf.buf = SendBuffer; buf.len = MESSAGE_SIZE; DWORD SendBytes = 0; // 送信先のIPアドレスとポート番号を設定 SockAddr.sin_family = AF_INET; SockAddr.sin_addr.s_addr = inet_addr( IP ); SockAddr.sin_port = htons( PORT ); // データグラムを送信する hr = WSASendTo( SocketID, &buf, 1, &SendBytes, 0, (SOCKADDR*)&SockAddr, // 送信先情報 AddrSize, NULL, NULL ); if( hr != 0 ) { sprintf_s( OutString, "WSASendTo()でエラー [ ErrorCode:%d ]\n", WSAGetLastError() ); OutputDebugString( OutString ); hr = -1; goto EXIT; } } // サーバーから受信 { WSABUF buf; buf.buf = RecvBuffer; buf.len = MESSAGE_SIZE; DWORD RecvBytes = 0; // データグラムを受信して送信元のアドレスを保存する hr = WSARecvFrom( SocketID, &buf, 1, &RecvBytes, 0, (SOCKADDR*)&SockAddr, // 送信先情報 &AddrSize, NULL, NULL ); if( hr != 0 ) { sprintf_s( OutString, "WSARecvFrom()でエラー [ ErrorCode:%d ]\n", WSAGetLastError() ); OutputDebugString( OutString ); hr = -1; goto EXIT; } } SYSTEMTIME st; ::GetLocalTime( &st ); sprintf_s( OutString, "%d:%d:%d:%d [ 送信:%s ][ 受信:%s ]\n", st.wHour, st.wSecond, st.wMinute, st.wMilliseconds, SendBuffer, RecvBuffer ); OutputDebugString( OutString ); } hr = 0; EXIT: // ソケットの切断 if( SocketID != INVALID_SOCKET ) { if( closesocket( SocketID ) != 0 ) { sprintf_s( OutString, "closesocket()でエラー [ ErrorCode:%d ]\n", WSAGetLastError() ); OutputDebugString( OutString ); } } // WS2_32.dllの開放 for( int i=0; i<WSAStartupCount; i++ ) { if( WSACleanup() != 0 ) { sprintf_s( OutString, "WSACleanup()でエラー [ ErrorCode:%d ]\n", WSAGetLastError() ); OutputDebugString( OutString ); } } return hr; }サーバー側アプリを実行してからクライアント側アプリを実行してください。