以下のようなコードを書きました。
UdpClientを使った2スレッド・ブロッキング通信ですが、相手先にICMP port unleachableを返すようなホスト:ポートの組み合わせを選びます(要するに相手サービスが死んでいるときのテストです)
SendしたあとICMPが戻ってくると、ブロックしていたReceiveがWSAECONNRESET(System.Net.Sockets.SocketException: 既存の接続はリモート ホストに強制的に切断されました) を投げます。これ自体は予期したことで、そのためにcatchしています。
問題はこれからで、それ以降Receiveを呼ぶと即座にWSAEWOULDBLOCK( System.Net.Sockets.SocketException: ブロック不可のソケット操作をすぐに完了できませんでした)を投げます。例外が例外なので、catchしたついでに、udp.Client.Blocking=true;とやってみると、期待した動作になります(パケットを待つようににある)。代入する前も、udp.Client.Blocking.ToString()は"true"とか云うので、内部で何か状態変化を戻し損ねているのでしょうか。
XP SP2と、Vista双方で、ファイヤーウォール無効 の条件で再現しますが、こういうものなんでしょうか。
#なんかタイトルがKBみたいな気がする・・・
Code Snippet
using System.Net;
using System.Net.Sockets;
class Test
{
static byte[] send = new byte[] { 0, 1, 2 };
static void Main(){
UdpClient udp = new UdpClient("localhost", 30000);
System.Threading.ThreadPool.QueueUserWorkItem(delegate(object o){
while (true){
System.Console.WriteLine("W");
udp.Send(send, send.Length);
System.Threading.Thread.Sleep(1000);
}
}, null);
while (true){
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
try {
byte[] b = udp.Receive(ref ep);
}catch (SocketException e){
System.Console.WriteLine(e.ToString());
}
}
}
}