こんにちは、KIMです。
WSARecv関数を使ってパケット取得しようと思ってやってるんですが、SOCKET_ERRORになって
しまいます。WSARecv failed. Code 10022と出力されます。
http://homepage2.nifty.com/spw/tips/PacketDump.html
上のところを参考にして同じようにしてるつもりなんですが。
ソースは下のとおりです。どなたかよろしくお願いいたします。
環境 windows2000 VisualC++.net MFC
WSABUF wsb;
DWORD Flags=0;
unsigned long len;
SOCKET sock;
wsb.buf=buf;
wsb.len=MAX_IP_SIZE;
memset(wsb.buf,0x0,MAX_IP_SIZE);
sock = WSASocket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);
if(SOCKET_ERROR == WSARecv(sock,&wsb,1,&len,&Flags,NULL,NULL)){
wsprintf(buf,\r\nWSARecv failed. Code %d \r\n,WSAGetLastError(),sock);
SendMessage(hEdit,EM_REPLACESEL,0,(LPARAM)buf);
continue;
}
初期化の部分をしてないからじゃないかな?
会さん、ありがとうございます。
初期化というのは len に何も入ってないからということですか?そうでしたら、いろいろ
MAX_IP_SIZE(65535)とか1、0とか入れてみても変わらないんです。
下記のところでもWSARecv使ってて参考にしたんですが、出来ませんでした。
http://www.ne.jp/asahi/yamashita/programming/
http://lxr.webperf.org/source.cgi/srclib/apr/network_io/win32/sendrecv.c
WSASocketの戻り値をチェックしていませんが、
有効な値が返ってきていますか?
初期化といわれているのは、
//Ver2.2 でWinSockを初期化する
WSAStartup(MAKEWORD(2,2),&wsd);
こっちの話ではないかと思うのですけれど。
提示されている中には確かに無いので。
例に挙げているHPのように別の場所でやっているのであれば良いのだと思いますが、
提示されているソースからはわかりませんから。
dairygoodsさん、PATIOさんありがとうございます。
>dairygoodsさん
書きませんでしたが、以下のようにして引っかからなかったので大丈夫だと思います。
sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);
if(INVALID_SOCKET == sock){
wsprintf(buf,WSASocket(AF_INET,SOCK_RAW) failed);
SendMessage(hEdit,EM_REPLACESEL,0,(LPARAM)buf);
}
>PATIOさん
ソケットの初期化は一番最初にしてあります。
はじめに貼ったリンクのソースをVC++で書き換えて、とりあえず同じようなものを作ろうと思
ってやっています。今のソースをリンクして全部載せたほうがいいですか?
量にもよりますけれど、載せられるものなら載せた方が話が早いと思います。
ただ、初期化の件であれば以下のようにしてコンストラクタでやってます。
といった形で追加掲載でも良いかと思います。
あと該当する一連の流れに関してはあまりはしょらないほうが良いと思いますよ。
書いていなかったエラー処理などは今回の処理の流れでも割と重要な部分だと
思います。
エラー処理の有無で疑うべき場所の絞込みが出来ますから。
WSARecv()でのWSAEINVALエラーの場合の説明として、
> The socket has not been bound (for example, with bind).
と書かれています。
掲示されたコードでは、どのホスト・ポートからのデータを受信しているのか不明ですが…
あるいは…
http://homepage2.nifty.com/spw/tips/PacketDump.html
のページのようにパケットダンプ(キャプチャ?)がしたいのでしょうか?
PATIOさん、瀬戸っぷさんありがとうございます。
>瀬戸っぷさん
> http://homepage2.nifty.com/spw/tips/PacketDump.html
>のページのようにパケットダンプ(キャプチャ?)がしたいのでしょうか?
そうです、そのまま同じようなものをVC++で作ろうとしてます。
>PATIOさん
以下にもう少し多く書きましたが、下のところに全部載せてみました。見づらいかと思いますが
よろしくお願いします。
http://www.geocities.jp/skyblue0745/Form1View.c
DWORD CaptureThread(void *phWnd) /*キャプチャスレッド*/
{
char buf[MAX_IP_SIZE]; /*MAX_IP_SIZE=65535*/
WSABUF wsb;
DWORD Flags;
unsigned long len;
SOCKET sock;
SYSTEMTIME t;
HWND hWnd =(HWND)phWnd;
HWND hEdit = GetDlgItem(hWnd,IDC_EDIT1);
CForm1View* hwnd1=(CForm1View*)phWnd;
sock= WSASocket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);
if( INVALID_SOCKET == sock){
wsprintf(buf,WSASocket(AF_INET,SOCK_RAW) failed);
SendMessage(hEdit,EM_REPLACESEL,0,(LPARAM)buf);
return -1;
}
while(1){
Sleep(1);
wsb.buf=buf;
wsb.len=MAX_IP_SIZE;
memset(wsb.buf,0x0,MAX_IP_SIZE);
Flags=0;
if(SOCKET_ERROR == WSARecv(sock,&wsb,1,&len,&Flags,NULL,NULL)){
wsprintf(buf,\r\nWSARecv failed. Code %d \r\n,WSAGetLastError(),sock);
SendMessage(hEdit,EM_REPLACESEL,0,(LPARAM)buf);
continue;
}
void CForm1View::OnBnClickedButton1()
{
DWORD tid;
HWND hwnd = GetSafeHwnd();
if(hThread == NULL){
if(-1 == InitAdapter())
return;
/*スレッド生成*/
hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)CaptureThread,hwnd,
0, &tid);
if(NULL != hThread)
return;
}
}
これってbind出来ていないのでは?
bindする対象のアダプタを選択してbindする部分がすっぱり抜けているような。
他のところでbindしても実際にWSARecvするsockがbindされていないのでは
駄目だと思いますけれど。
bindする処理がWSARecvを泣き別れではまずいと思うのは私の気のせい??
PATIOさん、度々ありがとうございます。
bindが出来ていないとのことですか。
元々、CForm1ViewクラスのInitAdapter()内でbindをしており、そこでのsockを使いたくて、
上記のように
CForm1View* hwnd1=(CForm1View*)phWnd;
として、hwnd1->sockという風にしてやってみたんです。でも、コンパイルは出来たんですが、
実行で以下のようなアプリケーションエラーが出てしまうのです。なので最初に書いたような
sockを新たに作るようにしてたのです。
0x00414ba0の命令が0x003e0562のメモリを参照しました。メモリがreadになることは
できませんでした。
多分クラスのポインタがちゃんと取得できていないからだとは思うんですがこの場合はどうした
らいいんでしょうか?
MFC使ったコトないし、WinSock2も使っていないですが…
とりあえず、
>KIM 2004/02/05(木) 16:08:41
での方法ではbind出来ていないハズです。
WSASocket()でソケット作ってからその後のwhileループに入るまでの間に、
CForm1ViewクラスのInitAdapter()内のbindが実行できるとは思えませんし、
そもそも作成したソケット(sock)を渡していないと意味が無いです。
(PATIOさんの指摘はそういうコトかと)
ただ……
> CForm1View* hwnd1=(CForm1View*)phWnd;
> として、hwnd1->sockという風にしてやってみたんです。でも、コンパイルは出来たんです
が、
コンパイル出来たコトがちょっと不明…ですが、
CForm1Viewクラスにsock変数があるのでしょうか??
(仮にあったとしても…CaptureThread()にあるsockとは別のモノになります)
bindに必要な情報をグローバル変数等で引き渡すようにして
スレッド側でバインドを取った方が良いような気もします。
その方が処理が一箇所に固まるので後でみた時にわかりやすいと思います。
スレッドはグロバール変数で情報の引渡しが出来ます。
但し、メインスレッド側とアクセスがバッティングしないように
排他が必要な場合が有りますので気をつけましょう。
さて、ポインタ渡しの件ですが、
そもそもCreateThreadで起動するスレッド関数の引数は決まっているはずです。
ところが、KIMさんのリンク先の関数は引数があっていない。
あと、参照したいならウインドウハンドルを渡しては駄目だと思いますけれど。
thisを渡すとかしないと駄目でしょう。(引数名が紛らわしいだけ?)
というか、その辺コードがないのでそうしているかもしれんけれど。
瀬戸っぷさん、PATIOさん、ありがとうございます。
ご指摘のとおりbindはスレッド内で行なうようにして少し手直ししたところ、パケットがきち
んと取得でき出力されるようになりました。
今までこちらでアドバイスをしていただいた皆さん、どうもありがとうございました。