- 締切済み
ソケット通信のオープンクローズ
MFC、VC6(WINXP)の環境でソケットプログラムを作成しています。 オープン処理として (1)ソケットの作成 (2)ノンブロッキングに変更 (3)タイムアウトを設定 (4)コネクト (5)セレクト クローズ処理として (1)シャットダウン (2)クローズソケット サーバーはアドレスが二つあり(2プログラム)とちらかが起動していなかったらもう一方のアドレスに接続する為、電文の送受信毎にオープン処理とクローズ処理を繰り返しています。 質問 (1)数百回オープンクローズを処理しているとオープン出来ない時があります。何故でしょうか? (2)指定したアドレスにサーバーソフトが立ち上がっていなかった時に コネクトのタイムアウトに時間がかかっているのでノンブロックに変更 しましたが間違いでしょうか?ブロッキングで対応できますか? VC初心者なので宜しくお願いします
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- nda23
- ベストアンサー率54% (777/1415)
ソケット系の処理全てについて間接呼び出しする必要があります。 //DLLのロード HMODULE hLib = LoadLibrary("WS2_32"); //名前でメソッドのアドレスを取得 SOCKET PASCAL FAR (*psocket)(int,int,int) = GetProcAddress(hLib,"socket"); //ポインタを使ったメソッドの呼び出し SOCKET hSocket = (*psocket)(PF_INET,SOCK_STREAM,IPPROTO_TCP); //DLLのアンロード(解放) FreeLibrary(hLib); あと、selectはポーリングなので、Windowsでは如何なものかと思い ます。WSAAsyncSelectを使って、イベントをウィンドウに受け取る 方法を用いるべきです。
- nda23
- ベストアンサー率54% (777/1415)
あぁ、直接呼び出してますね。実行時リンクです。 この方法ですと、DLLはプロセス空間に張り付いてしまうので、DLL内の 静的変数が破壊されても、除去する方法がありません。 実行中ロード方式にすることを薦めます。 MFCでどうやるか不明なのですが、DLLをロードして、そのハンドルから メソッドのポインタを求め、ポインタ経由でメソッドを実行します。 LoadLibrary、GetProcAddress 等を使う方法を検索してみてください。 実行中リンクは途中でDLL空間を破棄することができます。これには FreeLibraryを使います。再度、リンクすればDLL空間はリフレッシュ されるので、障害を引きずる心配はありません。 ソケットのように、実際には細かい制御が必要なプログラムで、MFCを 使うことには個人的にちょっと違和感があります。 と言うか、一つ一つのナマナマしい機能を知らないで、大丈夫かな? それと、通信なので、リリース後も色々な障害が発生しますが、 問い合わせに応えられるか、老婆心ながら心配です。
補足
nda23さん 有難う御座います。 >あぁ、直接呼び出してますね。実行時リンクです。 どの関数を動的リンクにすればいいのですか? ソケットの生成でしょうか? >一つ一つのナマナマしい機能を知らないで、大丈夫かな? それと、通信なので、リリース後も色々な障害が発生しますが、 コネクト、セレクトの手法に問題がありますか? このソースはネットでサンプルを見つけて自分なりに修正して使用 していますがご指摘の通り機能はほとんど知りません。 ご教示お願いします。
- nda23
- ベストアンサー率54% (777/1415)
(1)オープン出来ない時があります WinSockのDLLは内部に静的変数を持っているようで、特定の障害を 検出すると、内部変数が異常をきたし、以後の動作が不安定になる ことがあります。このため、実行時リンクはお勧めできません。 次のようなコーディングになっていませんか? WSAStartup(0x0202,&data); だとしたら、実行中リンクにしないと、安定した動作は得られません。 (2)サーバーソフトが立ち上がっていなかった時 >コネクトのタイムアウトに時間がかかっているので そんなにかかるもんですかねぇ?経験的に見て数秒でしょう。 非ブロッキングにするのはイイとして、どうやって制御してますか? ポーリングするようじゃダメですよ。WSAAsyncSelectを使うなら 話は分かります。receive以外はブロッキングでイイと思います。
お礼
#include <afxsock.h> // MFC のソケット拡張機能 の間違いでした
補足
nda23さん 有難うございます。 具体的なソースが有った方が解りやすいので貼り付けます。 (1)違う関数を使用しています (2)ノンブロックのオプションを付けないと最大40秒ほどconnextから返りません。 宜しくお願いします。 InitInstance()にて if (!AfxSocketInit()) { Dsp(IDP_SOCKETS_INIT_FAILED); return FALSE; } stdafx.hにて #include <afxcmn.h>{ SocktOpen() { MSG msg; int ConnctCount; int errno; unsigned long flag; int rcvsiz; int RetryCnt; RetryCnt = 0; int on = 1; flag=1; TOP: hSocket = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); if(hSocket == INVALID_SOCKET){ Dsp("soket create err"); goto NG_EXIT; } SOCKADDR_IN socin; socin.sin_family = AF_INET; socin.sin_port = htons( uiPortno); socin.sin_addr.s_addr = inet_addr(m_AdrsActive); //ノンブロックに変更 if(ioctlsocket(hSocket, FIONBIO, &flag)==SOCKET_ERROR){ fprintf(stderr,"ioctl(NONBLOCK) error:%d",WSAGetLastError()); } //タイムアウトを設定 setsockopt(hSocket, SOL_SOCKET,SO_REUSEADDR, (char * ) & on, sizeof (on)); ConnctCount = 0; CONNECT_RETRY: Dsp("soket sever line conect"); if(connect(hSocket, (PSOCKADDR)&socin,sizeof(socin))==SOCKET_ERROR){ errno=WSAGetLastError(); if(errno!=WSAEWOULDBLOCK) fprintf(stderr,"connect error:%d\n",errno); fd_set rmask,wmask;FD_ZERO(&rmask);FD_SET(hSocket,&rmask);wmask=rmask; struct timeval tv={ 1,0 }; int rc=select((int)hSocket+1, &rmask, &wmask, NULL, &tv); if(rc==SOCKET_ERROR) fprintf(stderr,"connect-select error:%d\n",WSAGetLastError()); if(rc==0){ /*time out proc*/ ConnctCount++; if(ConnctCount<5){ // Sleep(10); goto CONNECT_RETRY; }else{ Dsp("soket line conect err"); closesocket(hSocket); hSocket=INVALID_SOCKET; Dsp("socket saver line conect err happened、saver change"); goto NG_EXIT; } } if(rc==2){ //読み書きが同時に出来る場合 int val; int len=sizeof(val); if(getsockopt(hSocket,SOL_SOCKET,SO_ERROR,(char*)&val,&len)!=0) { // 既にデータが来ている }else{ // コネクト失敗 } } } //受信文字数を設定 rcvsiz = 8192; setsockopt(hSocket,SOL_SOCKET,SO_RCVBUF,(char*)&rcvsiz,sizeof(rcvsiz)); return 0; NG_EXIT:; while(::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){if(!AfxGetThread()->PumpMessage()){return 0;}} RetryCnt++; if(RetryCnt> 3){ Dsp(""3 times retry,sokcet line not open"); return 1; } if(SoketAddressFlg == 0){ m_AdrsActive = m_AdrsSecondary; SoketAddressFlg = 1; Dsp("soket saver change secondary"); }else{ m_AdrsActive = m_AddsPrimary; SoketAddressFlg = 0; Dsp("sokcet saver main change"); } goto TOP; } SocketClose() { shutdown(hSocket,1); if(closesocket(hSocket) == SOCKET_ERROR){ Dsp("soket close fail"); return FALSE; } hSocket = INVALID_SOCKET; return 0; }
補足
有難う御座います。 ハードル高いけど頑張ってみます。