こんにちは。
安易な質問かもしれませんが、ご教授ください。
-【環境】---------------------------------
OS : Windows Server 2008
ソフト : Visual Studio 2008 (VC++)
------------------------------------------
64ビット用のプロセスでSocket通信を作成しています。
select()でタイムアウト時間を指定して、
accept()で接続確認する箇所があるのですが、
select()の戻り値が-1となり、タイムアウト時間が有効にならず
accept()でブロック状態になってしまいます。
32ビット用のプロセスで動作すると、正常にタイムアウト時間まで
accept()を行い終了します。
64ビット用でselect()は使えないのでしょうか?
select()に代わるモノが64ビット用に存在するのでしょうか?
宜しくお願い致します。
・selectはx64でもつかえる
・とりあえず、最低限のソースを提示してみて
・x86とx64では変数の定義が変わってたりするので、select時に引数の内容を確認
たとえば、待ち時間指定に、他の変数からtimevalに代入してるなら
その際に値がおかしくなっていないか・・・など
・どういう流れかわからんが、SOCKET_ERRORが返ってきてるのにaccept作業させるのはお
かしいと思う
ご返信ありがとうございます!
抜粋ですが、ソースを提示します。
---------------------------------------------------------------------------
#include <winsock2.h>
SOCKET m_MySocket; // ソケット
SOCKET m_YourSocket; // ソケット
int SockAddrSize; // ソケットサイズ
fd_set fd;
timeval timeout;
int rtc;
// ■タイムアウト時間設定
FD_ZERO( &fd );
FD_SET( m_MySocket, &fd );
timeout.tv_sec = 0;
timeout.tv_usec = 500; //(500ミリ秒)
// ■select()
rtc = select( 1, &fd, NULL, NULL, &timeout );
(↑timeoutの中身は、tv_sec:0、tv_usec:500)
// ■accept()
SockAddrSize = sizeof( m_SockAddr );
m_YourSocket = accept( m_MySocket,
(struct sockaddr *)&m_SockAddr,
&SockAddrSize );
(…ここ↑でブロックし、以降↓に進まず…)
if( p_Main->m_YourSocket != INVALID_SOCKET ){
// ■データ送信処理
…
}
---------------------------------------------------------------------------
※select()の戻り値は-1ですが、今のトコロ無条件にaccept()しています。
ご指摘のほど、宜しくお願い致します。
見た限りでは問題は見つけられませんでした
selectのあとにWSAGetLastError()で、エラーを確認してみてください。
ソレと・・・ソースにはかかれてないから推測になるのですが
リスンソケットを作成などもエラーチェックなしでしょうか?
その場合、それらが正常に行われているかどうかは確認済みでしょうか?
selectより前の部分のエラーも確認してみてはどうでしょうか
select()以前のソースも追加して記載致します。
------------------------------------------------------------------------
#include <winsock2.h>
unsigned short port_no = 8001; // ポート番号
int rc; // リターンコード
WSADATA wWsaData; // WinSock情報
SOCKET m_MySocket; // ソケット
SOCKADDR_IN m_SockAddr; // ソケット情報
int SockAddrSize; // ソケットサイズ
fd_set fd;
timeval timeout;
int rtc;
// ①WinSockの初期化
if( WSAStartup( MAKEWORD(2,0), &wWsaData ) != 0 ){
rc = -1;
}
// ②ソケット生成
if( (m_MySocket = socket( PF_INET, SOCK_STREAM, 0 )) == INVALID_SOCKET ){
rc = -2;
}
// ③Bind
m_SockAddr.sin_family = PF_INET;
m_SockAddr.sin_port = htons(port_no);
m_SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
memset( m_SockAddr.sin_zero, 0x00, sizeof(m_SockAddr.sin_zero) );
if( bind( m_MySocket,
(struct sockaddr *)&m_SockAddr,
sizeof(m_SockAddr) ) != 0 ){
rc = -3;
}
// ④Listen
if( listen( m_MySocket, 5 ) != 0 ){
rc = -4;
}
// ■タイムアウト時間設定
FD_ZERO( &fd );
FD_SET( m_MySocket, &fd );
timeout.tv_sec = 0;
timeout.tv_usec = 500; //(500ミリ秒)
// ■select()
rtc = select( 1, &fd, NULL, NULL, &timeout );
// ▲(確認用エラーコード出力)
rtc = WSAGetLastError();
------------------------------------------------------------------------
ソースの①~④までは異常値が返ってこなかったので、
正常に行われていると思います。
また、select()後のWSAGetLastError()は
「10038(ソケット以外のものに対して操作を実行?)」でした。
差し支えなければ、、
select()が正常に動作するソースをご提示いただけないでしょうか(x64用)?
> 差し支えなければ、、
> select()が正常に動作するソースをご提示いただけないでしょうか(x64用)?
ソースの提示は出来なくても、何らかのサンプルはあるかと思います。
http://foldingforum.org/viewtopic.php?f=8&t=4187
海外版です
他にも探せばありそうです。
> timeout.tv_usec = 500; //(500ミリ秒)
ここマイクロ秒単位じゃなかったっけ?
ネットからサンプルを探してその通りにやってみましたが、
現象は変わらずです・・・。
いろいろと調査した結果、select()でのタイムアウトは諦め、
WSAAsyncSelect()でaccept()を非ブロック化することにします。
目的はaccept()でブロックしてしまうのを解消したかったので。。
以下、対策したソースです。
-----------------------------------------------------------------------------
(↓この部分を削除)
> FD_ZERO( &fd );
> FD_SET( m_MySocket, &fd );
> timeout.tv_sec = 0;
> timeout.tv_usec = 500; //(500ミリ秒)
> rtc = select( 1, &fd, NULL, NULL, &timeout );
(↓これに変える)
rtc = WSAAsyncSelect( m_MySocket, hWnd, WM_APP, FD_ACCEPT );
-----------------------------------------------------------------------------
何とも腑に落ちませんが、、やりたい事は解決しました。
ご返信していただいた方々ありがとうございました。
以下の環境で試してみましたが再現しませんでした。
まあ、OSが違うものですけど。
OS: Windows 7 Ultimate x64
開発ソフト: Visual Studio 2008 & 2010
ビルドターゲット: x86 & x64
> rtc = select( 1, &fd, NULL, NULL, &timeout );
selectの第一引数が怪しいといえば怪しいのですが、MSDNでは無視されるとありますし。
ちなみに、Berkeley Socketでは、ここはfd_setの要素数ではなく、
fd_setに格納されたデスクリプタ(≒ソケット)のうちの最大値 + 1となっています。
# Unixでは、ソケットの型はintなんです。
今回の例なら m_MySocket + 1。
あと、読んでいてちょっと不安になった部分があったため念のため指摘。
誤読だったらごめんなさい。
> select()でタイムアウト時間を指定して、
> accept()で接続確認する箇所があるのですが、
>
> select()の戻り値が-1となり、タイムアウト時間が有効にならず
> accept()でブロック状態になってしまいます。
ここを読む限り、select()はタイムアウト時間を設定するだけで
すぐに戻り、accept()を呼び出し時に接続が来なかった場合、
select()で指定したタイムアウト時間後にaccept()が戻る、と
考えているように思えました。
実際には、タイムアウトまで待つのはselect()の仕事です。
接続があればその場でselect()が返り、接続がなければタイムアウト
時間後にselect()が返ります。
どちらだったのかは戻り値で判定、と。
今回の例では、接続があったなら1、タイムアウトしたら0になります。
ありゃ、入れ違い……
ざっくりですが
***********************************************************
int SockRet;
fd_set Fds;
struct timeval WaitTime;
sockaddr_in dstAddr;
SOCKET Socket;
WaitTime.tv_sec = 1;
WaitTime.tv_usec = 0;
int dstAddrSize = sizeof(sockaddr_in);
while( WaitForSingleObject( *KillEvent , 0 ) == WAIT_TIMEOUT){
FD_ZERO( &Fds );
FD_SET( LisnSocket, &Fds );
SockRet = ::select( NULL , &Fds, (fd_set *)NULL, (fd_set *)NULL,
&WaitTime);
FD_CLR( LisnSocket, &Fds );
if (SockRet == 0){
continue;
}
if( SockRet ==SOCKET_ERROR){
/*エラー処理*/
}
//Accept
Socket= accept(LisnSocket, (struct sockaddr *) &dstAddr,
&dstAddrSize);
/*あと略*/
}
******************************************************
こんなです。
XP、win7かつ、ソリューション構成・OSともにx64で動いています。
開発は2008
64ビットOSでselectが使えないなんてことがあれば、
大きな話題になってると思うのですが
「Windows Server 2008」「x64」「SOCKET」「通信」「select」
といった単語を組み合わせてグーグル検索してみたのですが
似たような現象の話は見つかりませんでした。
で、
すでに32ビットで成功しているソースを使うのではなく
新しくソリューションをつくり、リスンソケット作成からselectするだけのものを作り
実験してみてはいかがでしょうか?
Windows Server 2008 x64でも試してみました。
インストール直後の状態(※)と、今日までの
Windows Updateを適用した状態(SP2)の2種類で
試しましたが、どちらもselect()が-1を返すことは
ありませんでした。
参考まで。
※ SPがいくつだったか調べておくのを忘れました。
更新履歴を見る限りSP2より前だとは思います。
7/12にMSDNからダウンロードしたisoイメージで
インストールしたものです。