我在套接字编程方面有点挣扎(我一点也不熟悉),我找不到任何可以从谷歌或 MSDN 中得到帮助的东西(糟糕)。为这篇文章的长度道歉。
基本上我有一个现有的服务,它通过 UDP 接收和响应请求。我根本无法改变这一点。
我的 web 应用程序中还有一个客户端,它调度和侦听对该服务的响应。我得到的现有客户端是一个单例,它创建一个套接字和一个响应槽数组,然后使用无限循环方法创建一个后台线程,该方法进行“sock.Receive()”调用并将接收到的数据推送到槽阵列。关于这方面的各种事情对我来说似乎都是错误的,无限线程破坏了我的单元测试,所以我试图用一个让它异步发送/接收的服务替换这个服务。
第 1 点:这是正确的方法吗?我想要一个非阻塞、可扩展、线程安全的服务。
我的第一次尝试大致是这样的,这有点工作,但我得到的数据总是比预期的短(即缓冲区没有请求的字节数)并且在处理时似乎抛出异常。
private Socket MyPreConfiguredSocket;
public object Query()
{
//build a request
this.MyPreConfiguredSocket.SendTo(MYREQUEST, packet.Length, SocketFlags.Multicast, this._target);
IAsyncResult h = this._sock.BeginReceiveFrom(response, 0, BUFFER_SIZE, SocketFlags.None, ref this._target, new AsyncCallback(ARecieve), this._sock);
if (!h.AsyncWaitHandle.WaitOne(TIMEOUT)) { throw new Exception("Timed out"); }
//process response data (always shortened)
}
private void ARecieve (IAsyncResult result)
{
int bytesreceived = (result as Socket).EndReceiveFrom(result, ref this._target);
}
我的第二次尝试是基于更多的谷歌拖网和我经常看到的这种递归模式,但这个版本总是超时!它永远不会到达 ARecieve。
public object Query()
{
//build a request
this.MyPreConfiguredSocket.SendTo(MYREQUEST, packet.Length, SocketFlags.Multicast, this._target);
State s = new State(this.MyPreConfiguredSocket);
this.MyPreConfiguredSocket.BeginReceiveFrom(s.Buffer, 0, BUFFER_SIZE, SocketFlags.None, ref this._target, new AsyncCallback(ARecieve), s);
if (!s.Flag.WaitOne(10000)) { throw new Exception("Timed out"); } //always thrown
//process response data
}
private void ARecieve (IAsyncResult result)
{
//never gets here!
State s = (result as State);
int bytesreceived = s.Sock.EndReceiveFrom(result, ref this._target);
if (bytesreceived > 0)
{
s.Received += bytesreceived;
this._sock.BeginReceiveFrom(s.Buffer, s.Received, BUFFER_SIZE, SocketFlags.None, ref this._target, new AsyncCallback(ARecieve), s);
}
else
{
s.Flag.Set();
}
}
private class State
{
public State(Socket sock)
{
this._sock = sock;
this._buffer = new byte[BUFFER_SIZE];
this._buffer.Initialize();
}
public Socket Sock;
public byte[] Buffer;
public ManualResetEvent Flag = new ManualResetEvent(false);
public int Received = 0;
}
第2点:很明显我弄错了。
第3点:我不确定我是否正确。来自远程服务的数据如何到达正确的监听线程?我需要为每个请求创建一个套接字吗?
走出我的舒适区。需要帮忙。