ソケットプログラミング
2013年12月30日:ネットワーク
コンピュータどうしで通信する際、ソケットを利用します。ソケットとは、電球を入れるいれものですね。あの電球とソケットのようにつなげるイメージをこめて、コンピュータどうしをつなげるのにソケットと命名したのでしょう。 さて、このソケットは「Windows、Mac」といったOSがもっているAPIを使用することで利用可能です。プログラマはこのソケットをプログラムに取り組めばコンピュータどうしの通信が可能となります。 ここでは、MFCを使ってソケットプログラミングを行います。具体的には、GoogleとソケットをつなげてHTMLファイルを読み込むプログラムを作ります。
WinSockを使えるようにする
WindowsではWinSockというソケットプログラミング用APIが用意されているのでこれを使います。
WinSockを使うには「WSock32.lib」をリンクする必要があります。
プロジェクトのプロパティのリンカーの入力にある追加の依存ファイルに「WSock32.lib」としてつなげましょう。 あとは
WinSock2.hをインクルードしておきます。
これで命令を使用できるようになります。
手順
プログラミングの手順は以下のようになります。
WinSockの初期化(WSAStartup関数)
WSAStartup関数でWinSockを初期化します。WSAStartup関数は以下のようになっています。 int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
- wVersionRequested:Winsockのバージョンを指定
- lpWSAData:WSADATA構造体へのポインタ
wVersionRequestedにはMAKEWORDマクロを使ってWinsockのバージョンを指定します。 WORD MAKEWORD(BYTE bLow,BYTE bHigh); lpWSADataにはWSADATA構造体と呼ばれるWindowsソケットに関する情報格納変数のポインタを指定します。
ソケットを作成する(socket関数)
WinSockの初期設定がすんだらソケットを準備します。ソケットの準備にはsocket関数を使います。 SOCKET socket(int af,int type,int protocol);
- af:アドレスファミリ、ここではインターネットなのでAF_INETを指定します。
- type:TCPを使うので、SOCK_STREAMを指定します。
- protocol:プロトコール、AF_INETのときは0を記入します。
ソケットをつなげる(connect関数)
ソケットを作成したら、サーバーとつなげます。その際にconnect関数を使用します。 int connect(SOCKET s, const struct sockaddr FAR *name, int namelen);
- s: ソケットの指定
- name: サーバー情報を設定したSOCKADDR_IN構造体を指定
- namelen: nameのサイズ
SOCKADDR_IN構造体にサーバー情報を指定して、つなげたいサーバーを教えます。
- sin_family: アドレスファミリ
- sin_port:ポート番号
- sin_addr:IPアドレス
メッセージをおくる(send関数)
サーバーに接続したら、メッセージをサーバーに送ります。その際にsend関数を使います。 int send(SOCKET s, const char FAR *buf,int len,int flags);
- s:ソケット
- buf:送信したい文字列
- len:bufのサイズ
- flags:0を指定
メッセージを受け取る(recv関数)
サーバーからメッセージを受け取ります。関数はrecvを使用します。 int recv(SOCKET s, char FAR *buf, int len, int flags);
- s:ソケット
- buf:受信したデータが格納される
- len:bufのサイズ
終了処理
最後にソケットを閉じたりWinSockの終了処理をしておわりです。
プログラム
では、以上の内容をプログラミングしていきます。以下にソースをのせます。
void CNetWorkDlg::OnBnClickedOk() { // TODO: ここにコントロール通知ハンドラー コードを追加します。 WSADATA wsaData; LPHOSTENT lpHost; SOCKET s; int nRtn; SOCKADDR_IN sockadd; char szServer[256],szURL[256],szStrRcv[1024]; char szStr[256]; u_short port=80; //ポート番号 //Webサーバー名 szServerとURLを入力 strcpy_s(szServer,CStringA("www.google.com")); strcpy_s(szURL,CStringA("http://www.google.com/")); //WinSockの初期化**************************** if(WSAStartup(MAKEWORD(1,1),&wsaData)!=0){ AfxMessageBox("WSAStartupエラー"); return; } //ソケットを開く***************************** s=socket(AF_INET,SOCK_STREAM,0); //AF_INET->アドレスファミリはインターネット, //SOCK_STREAM->TCPを使う //0->プロトコール:AF_INETなら0 if(s==INVALID_SOCKET){ AfxMessageBox("ソケットを開けません"); WSACleanup(); return; } lpHost=gethostbyname(szServer); if(lpHost==NULL){ AfxMessageBox("gethostbynameエラー"); WSACleanup(); return; } //メモリの確保とsockaddの設定**************** memset(&sockadd,0,sizeof(sockadd)); sockadd.sin_family=AF_INET; //アドレスファミリ(インターネットだからAF_INET) sockadd.sin_port=htons(port); //ポート番号 sockadd.sin_addr=*((LPIN_ADDR)*lpHost->h_addr_list); //サーバーアドレス //サーバーに接続***************************** if(connect(s,(PSOCKADDR)&sockadd,sizeof(sockadd))!=0){ closesocket(s); WSACleanup(); return; } //GET命令をサーバーに送る******************** wsprintf(szStr,"GET %s HTTP/1.0\r\n\r\n",szURL); nRtn=send(s,szStr,(int)strlen(szStr),0); while(1){ //メモリを確保しメッセージを受け取る***** memset(szStrRcv,'\0',sizeof(szStrRcv)); nRtn=recv(s,szStrRcv,(int)sizeof(szStrRcv)-1,0); if(nRtn==0){ break; } if(nRtn==SOCKET_ERROR){ AfxMessageBox("recvエラー"); break; } AfxMessageBox(szStrRcv); //表示 } closesocket(s); WSACleanup(); return; }
著者:安井 真人(やすい まさと)
@yasui_masatoさんをフォロー