アプリ版:「スタンプのみでお礼する」機能のリリースについて

疑問に思ったので教えて下さい。
以下のようにBeginReceive処理を複数回行うとエラーが発生します。
これは1つのポートにおけるバッファが限界に達したためなのでしょうか。
' 変数宣言
lUdpClient = New UDPState()
lUdpClient.netPoint = New Net.IPEndPoint(Net.IPAddress.Any, iLocalPort)
lUdpClient.udp = New Net.Sockets.UdpClient(lUdpClient.netPoint)

For i = 0 To 3000
lUdpClient.udp.BeginReceive(AddressOf SendData, lUdpClient)
Next

システムのバッファ領域が不足しているか、またはキューがいっぱいなため、ソケット操作を実行できませんでした。

A 回答 (4件)

> 一度Sendした場合、受信待ち状態が解除されるので、


> 再度BeginReceiveを呼び出しています。

元々コールバック関数中でBeginReceiveを呼び出しておらず,
その場合には一度だけコールバック関数が呼ばれるために,
Sendで受信待ち状態が解除されると勘違いした,ということはないですか。

UdpClient.Sendはsendto WinSock2 APIを呼び出すのですが,
このAPIはRecvFrom WinSock2 APIによるoverlapped I/Oを阻害しません。

わかりにくいなら,受信用のソケットと送信用のソケットを分離してしまうのも一つの方法だと思います。
    • good
    • 0
この回答へのお礼

大変申し訳ありません。

ご指摘の通り、BeginReceiveの認識に誤りがありました。
コールバック関数中でBeginReceiveは呼び出していたのですが、
送信処理でもBeginReceiveを呼び出していました。

Sendを実行すると受信待ちが解除されるのだと思っていました。
送信処理にあるBeginReceiveを削除したところ、正常に動作するようになりました。

いつも1時間で落ちていたのに4時間経っても問題ありません。

ありがとうございました。

お礼日時:2009/03/11 16:10

> lUdpClient.udp.BeginReceive(New System.AsyncCallback(AddressOf receivecallback), lUdpClient) #ここでエラー



ここは送信処理を行うのではないのですか?
どう見ても受信処理をさせようとしていますが。
実際に送信するつもりでBeginReceiveしていれば,
タイマーでBeginReceiveの呼び出しが蓄積していきますから例外が発生します。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

申し訳ありません。ソースが足りませんでした。
以下のように送信処理を行っています。

' リモートホストを指定してデータを送信
lUdpClient.udp.Send(sendBytes, sendBytes.Length, remoteHost, remotePort)

lUdpClient.udp.BeginReceive(New System.AsyncCallback(AddressOf receivecallback), lUdpClient) #ここでエラー

一度Sendした場合、受信待ち状態が解除されるので、
再度BeginReceiveを呼び出しています。

やはり送信処理中にBeginReceiveを使用しているのが原因なのでしょうか。
しかし、受信待ち状態にするにはこの方法しかないと思い、
仕方なくBeginReceiveを使用しています。

お礼日時:2009/03/11 12:53

大量にUdpClientでBeginReceiveさせ例外を起こさせたところ,どうもOS側のキューが不足しているようです。


# 手元の環境のソースだと,Socket.csの4967行目。
なので,ThreadPoolは関係ありませんでした。

WSARecvFrom APIのエラーにもWSAENOBUFSはないので,通常は起こらないと見られているのでしょう。


確実な解決策は,overlapped I/Oの数を減らすことしかないと思います。
まず,BeginReceiveをそれだけたくさん行う必要があるのでしょうか。

例えば,最大で3個程度作るだけにしてしまえば,この例外が起きることはなくなると思います。
# 20件/secであればこれでさばけると思いますが。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
送信処理はTimer、受信処理はBeginReceiveを使用しているのですが、
うまくいきません。

Private Sub SocketsReception()
' 変数宣言
lUdpClient = New UDPState()
lUdpClient.netPoint = New Net.IPEndPoint(Net.IPAddress.Any, iLocalPort)
lUdpClient.udp = New Net.Sockets.UdpClient(lUdpClient.netPoint)

' 受信処理開始
lUdpClient.udp.BeginReceive(New System.AsyncCallback(AddressOf receivecallback), lUdpClient)

End Sub

Public Sub receivecallback(ByVal AR As IAsyncResult)

Try
Dim ClientData As UDPState = New UDPState()
Dim LU As Net.Sockets.UdpClient = CType(AR.AsyncState, UDPState).udp
Dim LE As Net.IPEndPoint = CType(AR.AsyncState, UDPState).netPoint
Dim receiveBytes As Byte() = LU.EndReceive(AR, LE)
Dim receiveString As String = enc.GetString(receiveBytes)
Dim receiveAddress As System.Net.IPAddress = LE.Address

'---受信処理を行う---

lUdpClient.udp.BeginReceive(New System.AsyncCallback(AddressOf receivecallback), lUdpClient)

' データ異常の場合
Catch ex As System.Net.Sockets.SocketException
' 終了処理
Catch ex As Exception
End Try
End Sub


Private Sub Timer2_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer2.Tick

'---送信処理を行う---

lUdpClient.udp.BeginReceive(New System.AsyncCallback(AddressOf receivecallback), lUdpClient) #ここでエラー

' 送信エラー
Catch ex As System.Net.Sockets.SocketException
' 終了処理
lUdpClient.udp.Close()
SocketsReception()
End Try

bSendOn = False

End Sub

お礼日時:2009/03/11 11:11

えーっと,OSが認識するプロセッサの個数 (タスクマネージャのパフォーマンスタブのCPUの個数) はいくつですか。


これが3以下であれば,3001個もスレッドを非同期I/Oを同時に実行することはできません。
# 4以上でも,3001個も非同期I/Oを作るのが良いとは言えませんが。

可能であるならば,そもそもBeginReceiveの回数を減らし,コールバック関数で再度BeginReceiveするなどしてみてはどうでしょうか。

参考URL:http://msdn.microsoft.com/ja-jp/library/system.t …
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
デュアルコアですので2つになります。

>可能であるならば,そもそもBeginReceiveの回数を減らし,コールバック関数で再度BeginReceiveするなどしてみてはどうでしょうか。

コールバック関数で再度BeginReceiveを実行したところ1時間ほどで同じ下記エラーが発生しました。
1秒間に20回くらいUDPでデータを受信しているため、パケットの量が多すぎてエラーになったのでしょうか。

システムのバッファ領域が不足しているか、またはキューがいっぱいなため、ソケット操作を実行できませんでした。

お礼日時:2009/03/10 19:05

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!