
No.5ベストアンサー
- 回答日時:
>サーバ側のバッファサイズを1470にすることでエラーは出なくなりました
>が、lngRetの返り値は常に1470に・・・
C側のバッファで、固定長配列のsizeof()をとっているからだとおもう
strlen()をつかうか、std::string等の可変長コンテナをつかう
この回答への補足
ご指摘どおりサーバ側の処理で
sendto ( sock, buf, sizeof ( buf ), 0, ( struct sockaddr * ) & addr, sizeof ( addr ) );
としておりこれを
sendto ( sock, buf, strlen ( buf ), 0, ( struct sockaddr * ) & addr, sizeof ( addr ) );
とすることで希望通りの動作をすることができました
問題部分のほとんど全てを解決していただき本当にありがとうございます
No.4
- 回答日時:
参考URLでErr.LastDLLErrorをつかえみたいなことをBob Butlerさんが言っていますがどうなんでしょう。
WSAGetLastErrorとGetLastErrorはリンクしてるっぽい(いつも同じ値を返してくる)ので、そのへんがVBの例外処理機構に引っかかってこないように内部的にSetLastErrorしてるとか(推測)
ところで受信するたびにAsyncSelectしなおす必要あるんだろうか
参考URL:http://forums.devx.com/showthread.php?t=37954
この回答への補足
情報ありがとうございます
さっそく情報を元に確認してみました
---------------------------------------
lngRet = recvfrom(udpsock, ByVal buf, ByVal LenB(buf), 0, fromaddr, LenB(fromaddr))
If (lngRet > 0) Then
LbDiscv.Caption = "UPnP機器を検出しました"
ElseIf lngRet = SOCKET_ERROR Then
Label1.Caption = Err.LastDllError & " : " & WSAGetLastError()
End If
---------------------------------------
でクライアントのみ実行するとLabel1には
"10035 : 0"
の文字が・・・
サーバ、クライアント両方を起動させると
"10040 : 0"
となりました。
10035はWSAEWOULDBLOCK
10040はWSAEMSGSIZE
です、これで原因を知ることができました
よくこのような情報を見つけられますね、すごいです
あとはWSAEMSGSIZEの対処をすることでなんとか対応できそうです
ありがとうございます
AsyncSelectですが、起動してそのまま何もしなければ
送信にあわせ受信し続けるんですが、ウィンドウを移動させる
テキストボックス内でメニューを出す
ブレークで一時止めるなど、何かしらの動作をさせると
受信しなくなってしまうため、AsyncSelectを入れてます・・・
コレでもたまに受信しなくなるためタイマ内に入れている状態です
※変な仕様ですね・・・VB(6)は・・・
WSAEMSGSIZEですがUDPソケットの送信サイズ1470バイトを無視していたため起きていました。
サーバ側のバッファサイズを1470にすることでエラーは出なくなりました
が、lngRetの返り値は常に1470に・・・
エラーが出なければ大きな問題ではないためReplaceを使い対処します
いろいろとありがとうございます
No.3
- 回答日時:
>その状態でわざとrecvfromをすると返り値は相変わらず-1ですが
>bufの中身は 0x00*512 文字分で返ってきました
GetLastErrorで WSAEWOULDBLOCK が返っていたら -1 でも正常だと思います。
なぜならWSAAsyncSelectを呼んでソケットが非ブロッキングモード(戻り値をすぐに返すモード)になっているから。
受信データがないので、結果を返したくても返せず、関数は失敗と見なされるんじゃないでしょうか。
受信するまで制御を返すなというのであれば、ブロッキングモードを使用すべきです。
>前回(06/02)の時点では受信していたのですが・・・
このときのGetLastErrorは、ひょっとして 10014のWSAEFAULT だったんじゃないでしょうか?
recvfromの最後のパラメータがSOCKADDRのバイト長に満たないと、たぶんそうなるとおもいます。
SOFTBANKのWinsock2.0本(初版)にはfromlenを初期化しなくていいとか書いてあって、それでハマったことがあります。
この回答への補足
今までのやり取りに関することでは常に
recvfromの返り値は-1で
GetLastErrorではゼロが返っており
受信エラーが起き原因は不明という状態でコレの原因が不明でした
現在わかってる範囲で関係ありそうなのはバッファサイズです
現在はCサーバのバッファサイズは4096、VBクライアントは512としていますがこれを
Cのサーバのバッファサイズを
char buf [ 64 ];
VBのクライアントのバッファサイズを
Dim buf As String * 128
とし、recvfromをすると返り値は 64、サーバ側のバッファサイズが返ってきます
もちろんサーバのバッファサイズ内(64以下)に収めたデータを送信しています
おそらくVB側の受信データ取得サイズがバッファのサイズを越えているためrecvfromでエラーを吐くと思われますが
GetLastErrorではゼロになっております
No.2
- 回答日時:
recvfrom直前でのバッファ初期化忘れ?
もし、Winsock内部のバッファが消えてないのなら、受信データがおかしいとかの以前に、FD_READが送られ続けてアプリがフリーズするはず。
あと気になったのは(bufのタイプがわからないのでアレですが)、LenよりLenBを使うべきかと。
こちらで実験したところ、stringのときはマルチバイトを含む場合も文字数をかえしてしまうし、内部形式がバイト配列のVariantだと半分の長さしか返してきませんでした。
この回答への補足
返事が遅れてすみません
recvfromの前に初期化はしています
仰るとおり常にFD_READが起きていますがフリーズはせずDoEventsをかけた様な状態です。
VBの受信部分の詳細ですが
------------------------------------------------
Private Sub Data_Read()
Dim lngRet As Long
Dim portstr As String
Dim addrstr As String
Dim strErrMsg As String
Dim buf As String * 512
Dim buf2 As String
buf = ""
lngRet = recvfrom(udpsock, ByVal buf, ByVal LenB(buf), 0, fromaddr, LenB(fromaddr))
buf2 = Replace(buf, Chr(0), "")
Label3.Caption = buf2
If (lngRet > 0) Then
Label1.Caption = "接続されています"
ElseIf lngRet = SOCKET_ERROR Then
LbDiscv.Caption = ""
If WSAGetLastError() = WSAEWOULDBLOCK Then
Label1.Caption = "未接続"
ElseIf WSAGetLastError() > 0 Then
strErrMsg = "send:" & strWSAErrorGet(WSAGetLastError())
closesocket udpsock
lngRet = WSACleanup()
GoTo exitSend:
End If
Else
Exit Sub
End If
addrstr = CStr(fromaddr.sin_addr / &H1 Mod &H100) & "." & _
CStr(fromaddr.sin_addr / &H100 Mod &H100) & "." & _
CStr(fromaddr.sin_addr / &H10000 Mod &H100) & "." & _
CStr(fromaddr.sin_addr / &H1000000 Mod &H100)
portstr = CStr(ntohs(fromaddr.sin_port))
Label2.Caption = "address of " & addrstr & " : " & portstr
Call WSAAsyncSelect(udpsock, Text1.hWnd, &H100, FD_READ)
Exit Sub
exitSend:
On Error Resume Next
If strErrMsg <> "" Then
MsgBox strErrMsg, vbOKOnly + vbExclamation, App.Title
End If
End Sub
------------------------------------------------
このような感じです
上記でbufを初期化はしていますが
buf = "" としても内部は 0x00*512 文字分で埋まって
LenB の返り値は512で recvfrom の返り値は常に -1 です
おそらく String * 512 で宣言しているせいかと思われますがそうしないと受信できません
ただの String で初期化し、LenB() をするとゼロが返るためゼロ文字受信することになってしまいます
これも改善方法がわからない状態です
アドバイスどおりLenからLenBに変えてみました
さきほどサーバ、クライアントを起動した状態で
サーバを停止させるとクライアント側のFD_READも停止しました
その状態でわざとrecvfromをすると返り値は相変わらず-1ですが
bufの中身は 0x00*512 文字分で返ってきました
一応これを未受信状態と判断しておきます
しばらくコレで様子を見ます
前回(06/02)の時点では受信していたのですが・・・
おそらくソケットを使用してのデバッグ作業なので
途中でソケット自体ががおかしくなった為なのかもしれません・・・
聞く前に再起動をするべきでしたね・・・すみません
あとは一定時間受信できていなければ未接続と判定することで一応解決できそうです
アドバイスありがとうございます
2,3日締め切らずに置いておきます
何かご意見ご指摘があればよろしくお願いします
No.1
- 回答日時:
自信ないですが、フラグがMSG_PEEK(0x2)になっているとか?
この回答への補足
ご返事ありがとうございます
サーバ、クライアント共にフラグの設定はしていません
Cサーバ側
------------------------------------------------
sendto ( sock, buf, sizeof ( buf ), 0, ( struct sockaddr * ) & addr, sizeof ( addr ) ); /* サーバへデータと自分のアドレス情報を送信 */
------------------------------------------------
VBクライアント側
------------------------------------------------
recvfrom(udpsock, ByVal buf, ByVal Len(buf), 0, addr, Len(addr))
------------------------------------------------
といった感じです。
特におかしそうな部分は無いと思うのですが・・・
一応VB側の部分の詳細も書いておきます
------------------------------------------------
Call WSAStartup(&H101, musrStartup)
udpsock = socket(AF_INET, SOCK_DGRAM, 0)
addr.sin_family = AF_INET
addr.sin_port = htons(10000)
addr.sin_addr = INADDR_ANY
Call bind(udpsock, addr, Len(addr))
Call WSAAsyncSelect(udpsock, TextBox1.hWnd, &H100, FD_READ)
Call MemCopy(mreq, 0, Len(mreq))
mreq.imr_interface = INADDR_ANY
mreq.imr_multiaddr = inet_addr("239.192.1.2")
Call setsockopt(udpsock, IPPROTO_IP, IP_ADD_MEMBERSHIP, mreq, Len(mreq))
------------------------------------------------
としています(上記はエラー処理の部分などは端折って書いています)
TextBoxのKey_Downにハンドルを当て、反応があればrecvfromをしています
コレに関してはタイマーでも同様の動作をします
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C# シリアル通信でデータ受信...
-
winsockでソケット通信の開発を...
-
「スイッチングハブのバッファ...
-
socket: recvはいつ,どれだけ...
-
Linuxでのシリアル通信について...
-
recv関数の受信結果について
-
TCP/IP通信プログラミングにお...
-
TCPでの非同期型select関数につ...
-
ClearCommError呼び出し時のCE_...
-
シリアルポート通信
-
SocketのSend関数でのCLOSEの検...
-
WriteFile()でのデータ送信がで...
-
winsockの動作について。
-
SerialPortのDataReceivedイベ...
-
WinsockAPIのrecvfromの受信デ...
-
シリアル通信エラー
-
rs232cでの受信データ(mscomm)...
-
DirectXでの周波数(音程)変更
-
Macターミナルで実行中のプログ...
-
バックグラウンドのプロセスの...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C# シリアル通信でデータ受信...
-
winsockでソケット通信の開発を...
-
WriteFile()でのデータ送信がで...
-
シリアル通信の出力バッファと...
-
socket: recvはいつ,どれだけ...
-
「スイッチングハブのバッファ...
-
Linuxでのシリアル通信について...
-
COMポートの同時オープン同時読...
-
シリアル通信エラー
-
SerialPortのDataReceivedイベ...
-
【CAsyncSocket::OnReceive()呼...
-
ソケット通信内 read関数について
-
ftplibのエラー処理
-
recv関数の受信結果について
-
rs232cでの受信データ(mscomm)...
-
UDP処理のエラーについて
-
SocketのSend関数でのCLOSEの検...
-
TCP/IP通信プログラミングにお...
-
winsockの動作について。
-
シリアル通信 大きいサイズの...
おすすめ情報