C++ MFC PC間ネットワーク通信に関する問題

このQ&Aのポイント
  • C++ MFCでPC間のネットワーク通信を行う際に問題が発生しています。
  • 参考にした通信プログラムを組んだが、一部変更してもうまくいかない。
  • MSDNを見ても解決策が見つからないため、助けを求めています。
回答を見る
  • ベストアンサー

C++ MFC PC間ネットワーク通信に関して

gaku_2011と申します。初めて投稿します。よろしくお願いします。 C++歴1年です。まだ初級レベルです。 現在、Visual Studio2005でC++ MFCでダイアログベースでプログラムを組んでいるのですが、今回初めて PC間のネットワーク通信をすることになって困っています。 http://www.g-ishihara.com/mfc_ge_02.htm さんの所にある通信プログラムを参考に組んだところ すべて正常に動作しました。非常に参考になりました。(ASyncSocketクラスを参考にしています。) 今後クライアント側の台数を複数台に増やすことを考えて、接続してきたクライアントのIPアドレス 等を得ようと下記のように一部変更して構造体の中を覗こうとしようとしたのですがうまくいきません。 m_lsnSock.Accept(*m_conSockP)のようになっていたAccept関数を m_lsnSock.Accept(*m_conSockP,lpSockAddr ,lpSockAddrLen)のように変数を追加したら ”lpSockAddr ,lpSockAddrLen側に相手側の情報が入ってくる”と他のホームページに読んだ ような気がしたので修正してやってみました。 lpSockAddr ,lpSockAddrLenは SOCKADDR *lpSockAddr = 0; SOCKADDR SockAddr; lpSockAddr = &SockAddr; int SockAddrLen; int *lpSockAddrLen = 0; lpSockAddrLen = &SockAddrLen; のように作ったのですが。 コンパイルは正常に出来ました。 デバッグモードでAccept()関数の直後でとめて関数の戻り値をみるとfalseで戻ってきてしまいます。 m_lsnSock.Accept(*m_conSockP)ではtrueが戻ってきています。 何か追加した変数の作り方がおかしいのでしょうか? MSDNも覗いたのですが、なかなか中身が理解できないので投稿しました。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

> デバッグモードでAccept()関数の直後でとめて関数の戻り値をみるとfalseで戻ってきてしまいます。 そのときのエラー・コードは? マニュアル読みましたか? > int SockAddrLen; int SockAddrLen = sizeof(SOCKADDR); ではなくて?

参考URL:
http://msdn.microsoft.com/ja-jp/library/eczhacdy(v=VS.90).aspx
gaku_2011
質問者

お礼

int SockAddrLen = sizeof(SOCKADDR);のように修正しましたら 正常に相手のIPアドレスが読めるようになりました。 一応、参考URLの所は読んだのですが、理解力が足らないようです。 動作してから読んでみると、”なるほど”と思うのですが。 これで前に進むことが出来ます。 ありがとうございました。

その他の回答 (1)

  • sygh
  • ベストアンサー率76% (42/55)
回答No.2

CAsyncSocket::Accept() の第3引数は In/Out パラメータです。Out パラメータではありません。 CAsyncSocket::Accept() の内部で使用されているソケット関数 accept() の宣言部、具体的には Windows SDK の WinSock.h の 745 行目あたりを参照してください。 SAL 注釈で __inout_opt という修飾がなされています。 したがって正しい引数の指定方法は下記になります。 SOCKADDR clientSockAddr = {}; int sockAddrLen = sizeof(clientSockAddr); m_lsnSock.Accept(*m_conSockP, &clientSockAddr, &sockAddrLen); そもそも MSDN というか MFC の説明の仕方に問題があるのですが、そういうときは常に実装を参考にするようにしてください。 MFC はソースコードが開発者に公開されているせいなのか、ヘルプがどれもおざなりになっています。 ちなみにソケット API がなんでこんな面倒な引数の指定方法になっているかというと、クロスプラットフォーム API であるバークレーソケットの歴史が絡んできます。 主に、FreeBSD、Linux、Windows などでのソケットの実装の違いを吸収するためです。 なお、蛇足ですが、C/C++ においてローカル変数名はあまり大文字で始めない方がいいです。

参考URL:
http://wisdom.sakura.ne.jp/system/winapi/winsock/winSock5.html
gaku_2011
質問者

お礼

一応、最初のepistemeさんのメールのように変数を変更したら相手のIPアドレスが 読めるようになりました。 MSDNを読むには、まだ力不足のようです。 メールにある 参考URL:http://wisdom.sakura.ne.jp/system/winapi/winsock/winSock5.html も参考にさせて頂いて、これからもC++の勉強をしていこうと思います。 ありがとうございました。

関連するQ&A

  • MFCでソケット通信がしたいのですができません

    http://www.g-ishihara.com/mfc_nw_01.htm このサイトを参考に作っているのですが、次のようなエラーメッセージが出て動きません。 「Error : この操作を正しく終了しました。」 これはどういう意味でしょう? 調べてもよくわかりません。 ちなみに各エディットボックスの変数値はすべて、CString,Value型にしています。

  • UDP通信について

    UDP通信で困っています。 TCP/IP通信はすぐにうまくいったのですが、 UDPの簡単なサンプルがちゃんと動きません。 間違いがあればご指摘ください。 よろしくお願いします。 (クライアント側ソース int sock; struct sockaddr_in din; memset(&din, 0, sizeof(din)); din.sin_port = htons(50050); din.sin_family = AF_INET; din.sin_addr.s_addr = inet_addr("サーバーIP"); sock = socket(AF_INET, SOCK_DGRAM, 0); int buf = 12345; sendto(sock,(char*)&buf,sizeof(int),0,(struct sockaddr*)&din,sizeof(struct sockaddr_in)); (サーバー側ソース int sock; struct sockaddr_in sin; sock = socket(AF_INET, SOCK_DGRAM, 0); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(50050); sin.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { return(1); } struct sockaddr_in fromaddr; socklen_t len = sizeof(struct sockaddr_in); int buf; recvfrom(sock,(char*)&buf,sizeof(int),0,(struct sockaddr*)&fromaddr,&len); printf("recv:%d\n",buf);

  • c言語のaccept関数が待機を行いません

    c言語のaccept関数が待機を行いません 現在C言語によるプログラミングを勉強中で、 「Windows ゲームプログラミング」という書籍を教材に ネットワーク通信のプログラミングを行っております。 ネットワーク通信のプログラミングは初めてで 現在一つの壁にぶつかっております。 どうか護教授をお願い致します。 下記のサーバー側のコードですが、 (1)ソケットを作成して、bind関数でアドレスと関連付ける (2)listen関数で接続を準備する (3)accept関数でクライアントが接続するまで待機する (4)while文の中でクライアントからのメッセージを受け取る という目的で作成いたしましたが、クライアントからの接続はしていないはずなんですが、 どうもaccept関数で待機を行わず、while文に進んでしまい、無限ループに突入してしまいます。 accept関数の戻り値を確認すると「INVALID_SOCKET」でした。 現在はこのサーバーに接続するシステムは作成していないので接続はないと思います。 ポート番号などを変更してもダメでした。 お恥ずかしい質問かもしれませんが、どうかよろしくお願い致します。 以下コード WSADATA wsaData; sturuct sockaddr_in hostAddr,clAddr; SOCKET s,client; char buffer[1024]; int length; if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0) return; (1) s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); hostAddr.sin_family=AF_INET; hostAddr.sin_port=ポート番号; hostAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); bind(s,&hostAddr,sizeof(struct sockaddr_in)); (2) listen(s,1); printf("クライアントからの接続を待機...\n"); (3) client=accept(s,&clAddr,&length); printf("クライアントからの接続を確認\n受信を待機...\n"); (4) while(1){ length=recv(client,buffer,1024,0); buffer[length]=0; printf("文字列を受信:%s\n",buffer); if(strcmp(buffer,"exit")==0) break; } shutdown(client,SD_BOTH); closesocket(client); closesocket(s); WSACleanup(); return 0;

  • winsock2 非同期処理について

    教えてください。 winsockを使用して、ネットワーク間のアプリを作成しているのですが、 wndPorcが処理されないため困っています。 お分かりになる方教えてくださいませ。 送信側はメッセージを送っていますが、受信側のaccept処理が出来ません。(wndProcが呼ばれない) wndPorc関数って呼び出しって必要でしたか??? [環境] OS windows2000 Visual C++ 6.0 MFC [ソース] [.cpp内部] bool CSysCp02Dlg::NetWork_LogOn() { struct sockaddr_in server; // winsock初期処理 // ソケット作成 // 非同期処理 if(WSAAsyncSelect(server_s,this->m_hWnd,FM_TCPPROC,FD_ACCEPT|FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE) == SOCKET_ERROR){  return false; } // 構造体をクリア // 設定 // bind処理 // 受付開始(listen処理) return true; } LRESULT CALLBACK CSysCp02Dlg::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) <----ここの関数が処理されない。 { struct sockaddr_in client; int n; char Recv_Buffer[RECV_SIZE]; int nLength = sizeof(client); switch(message) { case FM_TCPPROC: switch( lParam ){ case FD_ACCEPT: client_s = accept(server_s, (struct sockaddr *)&client, &nLength); if(client_s == INVALID_SOCKET){ ErrNum = WSAGetLastError(); } break; } } return WndProc(hWnd, message, wParam, lParam); } 800文字以内に入りきらないため、略してあります。

  • WinSockでの通信プログラムがうまくいきません

    WinSockでの通信プログラムがうまくいきません。 使用言語はC++とDirectXです。 ローカルでの通信(ルータを介したパソコン同士)はうまくいくんですが、別の場所にあるPCとの通信ができません。 以下実際に使用している関数です。 関数はマルチスレッドで動かしています。 WSADATA mWsaData; SOCKET mSockYou,mSockI; struct sockaddr_in mAddr; struct sockaddr_in mServer; struct sockaddr_in mClient; void CNetwork::Init(){ int err = WSAStartup( MAKEWORD( 2, 0 ), &mWsaData ); if( err != 0 ){ ERROR_EXIT(); return; } //Socket初期化 mSockI = socket( AF_INET, SOCK_STREAM, 0 ); if( mSockI == INVALID_SOCKET ){ ERROR_EXIT(); return; } mPort = 0; memset( mName, 0, sizeof( mName ) ); } //Server側 void CNetwork::Accept(){ FILE* fp; fopen_s( &fp, "messageLog.txt", "w" ); mAddr.sin_family = AF_INET; mAddr.sin_port = htons( mPort ); mAddr.sin_addr.S_un.S_addr = INADDR_ANY; if( bind( mSockI, (struct sockaddr *)&mAddr, sizeof( mAddr ) ) ) fprintf_s( fp, "bind失敗\n" ); if( listen( mSockI, 10 ) != 0 ) fprintf_s( fp, "listen失敗\n" ); int len = sizeof( mClient ); SOCKET t = accept( mSockI, (struct sockaddr*)&mClient, &len ); if( t == INVALID_SOCKET ) fprintf_s( fp, "Accept失敗\n" ); mSockYou = t; fprintf_s( fp, "Accept終了\n" ); fclose( fp ); } void CNetwork::Connect(){ FILE* fp; fopen_s( &fp, "messageLog.txt", "a" ); fprintf_s( fp, "Connect開始\n" ); //ソケットの設定 mServer.sin_family = AF_INET; mServer.sin_port = htons( mPort ); mServer.sin_addr.S_un.S_addr = inet_addr( mName ); if (mServer.sin_addr.S_un.S_addr == 0xffffffff) { fprintf_s( fp, "hostbynameへ\n" ); struct hostent *host; host = gethostbyname( mName ); if ( host == NULL ) { return false; } mServer.sin_addr.S_un.S_addr = *(unsigned int *)host->h_addr_list[0]; } fprintf_s( fp, "Socketの設定完了\n" ); while( true ){ fprintf_s( fp, "connect()開始\n" ); if( connect( mSockI, (struct sockaddr *)&mServer, sizeof( mServer ) ) == 0 ){ fprintf_s( fp, "Connect完了\n" ); break; } else{ fprintf_s( fp, "Connect失敗\n" ); Sleep(100); } } fprintf_s( fp, "Connect終了\n" ); fclose(fp); } また、ログは下のように出ました。 //サーバ側 Accept失敗 //クライアント側 Connect開始 Socketの設定完了 connect()開始 Connect失敗 ご教授お願いします。

  • ソケット通信でチャットプログラム(unix c言語)

    c言語のソケット通信でチャットプログラムを作り中です 仕様:あるクライアントからメッセージがサーバに送信された時点でサーバは接続されたいる全てのクライアントにメッセージを送信する。 以下のようにクライアントからの接続(accept)がある度に、その返り値であるファイルディスクリプタにに対するreadと全クライアントに対するwriteの処理を行うchild関数をforkで起動します。これだとforkが起動した時点での全てのファイルディスクリプタ(接続されている全クライアント)の情報をchild関数に渡せますが、それ以降増え続けていくファイルディスクリプタの情報をchild関数に渡せないので、最初の方に接続したクライアントからのメッセージをそれ以降接続した他のクライアントに送信できないという状態です。 main() {   socket()   bind()   listen()     while(1){       accept()       if(fork()==0) {        child()       }     } } child() {   select()   if(FD_ISSET()) {     read()     write()   } } ※forkやソケット通信に関してかなり初心者なので、ソースや説明分が意味不明かもしれませんがよろしくお願いします。

  • C言語のsendとrecv

    C言語でクライアントとサーバのプログラムを作りたいのですが、かなりの初心者なので、とりあえず練習用として、クライアント側に整数を入力すると、サーバ側でその整数を二乗して、結果をクライアント側に返すという簡単なプログラムを作ろうと思いました。 ソケットの作成、通信ドメインの指定等は、参考書を見ながら(というか、ほとんど丸写しみたいな感じなんですが…)、なんとかできたんですが、sendとrecvで整数を送受信するにはどうすればいいのかが分かりません。 私が持っている参考書には、 int send(SOCKETS const char FAR *buf int len int flags); int recv(SOCKETS char FAR *buf int len int flags); とあるのですが、const char FAR *buf、int len、char FAR *bufのところがよく分からないのです。 例えば、a=1000を送信したい場合、aはchar型ではないのでsendでは送れないのですか? ほんと初心者ですいませんが、どなたか教えてください。 よろしくお願いします。

  • コンソールアプリケーションで通信したい

    クライエントプログラムを起動もしていないのに、アクセスがありましたと表示されます。 どこが悪いのか教えてくださいませんでしょうか? サーバー側 #include <stdio.h> #include <winsock2.h> int main() { WSADATA wsaData; LPHOSTENT host; SOCKET s; SOCKADDR_IN name = { AF_INET } , client; int client_addr=sizeof(SOCKADDR_IN); SOCKADDR_IN addr,addr2; addr.sin_family=AF_INET; addr.sin_port=2048; IN_ADDR ip;//実際と異なるアドレス ip.S_un.S_un_b.s_b1=180; ip.S_un.S_un_b.s_b2=328; ip.S_un.S_un_b.s_b3=9; ip.S_un.S_un_b.s_b4=56; addr.sin_addr=ip; WSAStartup(2 , &wsaData); s = socket(AF_INET , SOCK_STREAM , 0); bind(s , (SOCKADDR *)&addr , sizeof(addr)); listen(s , 1); int sizeaddr2=sizeof(addr2); accept(s , (SOCKADDR *)&addr2 , &sizeaddr2); printf("アクセスがありました\nポート %d : アドレス = %s\n" ,addr.sin_port , inet_ntoa(addr.sin_addr)); shutdown(s , SD_BOTH); closesocket(s); WSACleanup(); getchar(); return 0; } クライエント側 #include <stdio.h> #include <winsock2.h> int main() { while(1) { WSADATA wsaData; SOCKET s; WSAStartup(2 , &wsaData); s = socket(AF_INET,SOCK_STREAM , 0); IN_ADDR ip;//実際と異なるアドレス ip.S_un.S_un_b.s_b1=180; ip.S_un.S_un_b.s_b2=328; ip.S_un.S_un_b.s_b3=9; ip.S_un.S_un_b.s_b4=57; SOCKADDR_IN addr; addr.sin_family=AF_INET; addr.sin_port=2048; addr.sin_addr=ip; connect(s,(PSOCKADDR)&addr,sizeof(SOCKADDR)); send(s,"OK",3,0); shutdown(s , SD_BOTH); closesocket(s); WSACleanup(); } return 0; }

  • TCP/IP通信型電話番号検索プログラムを作りたいです。

    TCP/IP通信型電話番号検索プログラムを作りたいです。 クライアントは以下のようで大丈夫みたいなのですが、サーバの方を修正しなければなりません。 この質問で「TCP/IP通信型大文字・小文字変換プログラム」を発見しました。 サーバー側プログラム #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #define SOCK_NAME "./socket" int main() { int i; int fd1, fd2; struct sockaddr_in saddr; struct sockaddr_in caddr; int len; int ret; char buf[1024]; if((fd1 =socket(AF_INET, SOCK_STREAM, 0)) < 0 ){ perror("socket"); exit(1); } memset((char *)&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr=INADDR_ANY; saddr.sin_port=htons(1357); unlink(SOCK_NAME); if(bind(fd1, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { perror("bind"); exit(1); } if(listen(fd1,5) < 0 ) { perror("listen"); exit(1); } while(1){ len = sizeof(caddr); if((fd2 = accept(fd1, (struct sockaddr *)&caddr, &len)) < 0){ perror("accept"); exit(1); } fprintf(stderr, "Connection established: socket %d used.\n", fd2); while((ret = read(fd2, buf, 1024)) > 0 ){ fprintf(stderr, "read: &s\n", buf); for(i=0; i<ret; i++) if(islower(buf[i])) buf[i] = toupper(buf[i]); if(isupper(buf[i])) buf[i] = tolower(buf[i]); fprintf(stderr, "write: %s\n", buf); write(fd2, buf, 1024); } close(fd2); } close(fd1); return 0; } 先生によると、クライアントは同じもので良いそうです。 誰か、助けて下さい。

  • winsockの非同期処理について

    winsockで双方向通信のため、非同期処理を行っているのですが、うまくいきません。 クライアント側で、WSAAsyncSelectの処理の後、Connectを呼んでいるのですが、Connectでエラーメッセージを返します。(エラーナンバー: 10035) サーバ側はaccept処理はうまくいっているのですが、accept後うまく処理を返していないためだと思うのですが... で質問は、 1.クライアント側、サーバ側にそれぞれ、WSAAsyncSelect を記載しても問題ないか? クライアント側はConnect前で宣言。 サーバ側はbind前で宣言しています。 2.エラー番号10035は非ブロッキングモードで処理されないためにおきています。 Connectで非ブロッキングモード処理がされていないためだと思うのですが、他に記述しないといけない関数があるのでしょうか? クライアント側: // 非同期処理 if(WSAAsyncSelect(client_s,this->m_hWnd, FM_TCPPROC, FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR){ return FALSE; } // コネクト処理 memset(&client,0,sizeof(client)); client.sin_family = AF_INET; client.sin_addr.s_addr = inet_addr(IpAddress); client.sin_port = htons(PORT_NO); if(connect(client_s, (LPSOCKADDR)&client, sizeof(client)) == SOCKET_ERROR){ <-- ここでエラー long ErrNum = WSAGetLastError(); <-- ここでエラーNoがかえる。 return FALSE; }else{ NetFlg = true; } お分かりになる方教えてくださいませ。よろしくお願いします。

専門家に質問してみよう