よろしくお願いします。
環境は、
Windows 7 Pro 64bit
Visual Studio 2010 Pro (VC++)
を使用しております。
64ビット用のプロセスでSocket通信を作成しておりますが、
構造体メンバーのアライメントを4バイトで作成すると、
select()で失敗するようになってしまいます。
※もしかしたら、select()失敗の原因は、FD_ZEROもしくはFD_SET?(憶測)
「構造体メンバーのアライメントを4バイトにしたまま」で、
selectを使用する方法。または、select()の代わりとなる関数を使用する方法。
をご存知の方がいましたら教えていただけないでしょうか?
下記に簡単なコードを記述させて頂きます。
------------------------------------------------------------------
#include <winsock2.h>
unsigned short port_no = 8050; // ポート番号
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;
// ここのselect()が-1を返します
rtc = select( 1, &fd, NULL, NULL, &timeout );
// エラーコードは10038が返ってきます
// エラーコードの内容
// ソケット以外に対して操作が試行されました。
// ソケット ハンドル パラメータの参照先のソケットが有効ではないか、
// fd_set のメンバが有効ではありません。
rtc = WSAGetLastError();
-------------------------------------------------------------------
>rtc = select( 1, &fd, NULL, NULL, &timeout );
rtc = select( m_MySocket + 1, &fd, NULL, NULL, &timeout );
ではないのですか。そ~いう簡単な問題じゃないか(vv;)。
仲澤@失業者さん
御指摘ありがとうございます。
第1引数は無視される仕様だったと思いますが、
お教え頂いた内容で修正して動作させてみました。
結果は、やはりselect()で-1を返してしまいます。
そうなると本格的に
#pragma pack( push, 4)
~
#pragma pack( pop)
の問題となり、WinSockを含めて、外部ライブラリの定義に対して
上のパックを「かけている」可能性があります。
当然ですが、それはあってはならないことです。
この認識は大丈夫ですか?。
仲澤@失業者さん
御指摘ありがとうございます。
>#pragma pack( push, 4)
> ~
>#pragma pack( pop)
>の問題となり、WinSockを含めて、外部ライブラリの定義に対して
>上のパックを「かけている」可能性があります。
>当然ですが、それはあってはならないことです。
>この認識は大丈夫ですか?。
構造体メンバーのアライメントに関しては、
ソースコードに#pragma packを使用しておらず、
VisualStudio2010開発環境(プロジェクト)設定の、
コンパイラオプション(/Zp)で設定しております。
【参考URL】
http://msdn.microsoft.com/ja-jp/library/xh3e3fd0.aspx
>コンパイラオプション(/Zp)で設定しております。
その方法では、自前のソース以外の、DLL、ライブラリを使用する
ことはできません。それらの外部のバイナリ内の各オブジェクトの
オフセット位置は、それらがコンパイルされたときに決定されています。
つまり出荷時に固定されているわけです。
Zpを指定したからと言って、それらのあらためてコンパイルされない
DLLやLibのアライメントが調整されるわけではありません。
Zpが安全に使える場合とは「一切の外部ライブラリとソースを使用しないで、
自前のコードのみをコンパイルするプロジェクト」だけです。
まず、Zpを外し、自分のコードの必要な部分だけに#pragma(・・・)
しましょう。
この方法が、Windowsアプリを作成する場合の唯一のパック方法
となります。
気になっているところが、
64BIT版って、ヘッダーファイルのディレクトリーが別になっている場合って
ありませんでしたっけ?
「winsock2.h」なんてありそうですよね?
仲澤@失業者さん
御教授ありがとうございます。
>Zpが安全に使える場合とは「一切の外部ライブラリとソースを使用しないで、
>自前のコードのみをコンパイルするプロジェクト」だけです。
Zpの使用はかなり制限される事になるのですね。
>まず、Zpを外し、自分のコードの必要な部分だけに#pragma(・・・)
>しましょう。
>この方法が、Windowsアプリを作成する場合の唯一のパック方法
>となります。
承知いたしました。
上記方法(#pragma)で対処していく事にしようと思います。
詳しく丁寧にお答え頂き、ありがとうございました。
ITOさん
御教授ありがとうございます。
>気になっているところが、
>64BIT版って、ヘッダーファイルのディレクトリーが別になっている場合って
>ありませんでしたっけ?
>「winsock2.h」なんてありそうですよね?
ヘッダーファイルによっては別になっている事があるのでしょうか。
「winsock2.h」が入っているディレクトリーは一箇所しか見つける事ができませんでした。
ヘッダーは#ifdefで切り分けのようです(_WIN64とか)。
Libは当然分かれてますけど。
Winsock2.hは、当たり前ですが独自に#pragma pack()はしません。
アライメントはデフォルトの8Byte(だったかな)に固定のはず。
そもそも何のために4Byteにしたいのかが不明ですが。
一般にそれが必要になるのは、ストリーム(ファイル、通信)などの
データが、そうなっている場合などに限られるはずで、その場合でも
通信や保管読み込み対象のstructをパックするのが普通です。
つまり、一般に、Zpを使う機会はまったくないと断言できます。