SocketAsyncEventArgs.UserToken未被更新

本文关键字:更新 UserToken SocketAsyncEventArgs | 更新日期: 2023-09-27 18:10:16

我目前有一个客户端-服务器应用程序,它涉及一个Silverlight客户端和一个。net服务器。. net部分使用System.Net.Sockets命名空间中提供的Tcp类,而Silverlight客户端使用原始套接字。我从目前使用HttpListener类的代码移植到此,因为它不适合我的需要。但是,Http类在SL端具有使用Begin*和End*样式异步方法的能力,这些方法允许我在操作完成后指定处理程序。我在使用新系统时遇到了麻烦。我目前的策略是将处理程序作为UserToken的一部分。然而,这个令牌似乎没有得到更新。

这里是一些编辑过的代码。我能够让双方相互交谈,但似乎没有发送正确的UserToken。

public class ClientUserToken
{
    public Handler Handler { get; set; }
    public string Test { get; set; }
    public ClientUserToken(Handler handler, string test)
    {
        Handler = handler;
        Test = test;
    }
}
public class SocketClient
{
    private Socket _clientSocket;
    private string _ipAddress;
    private int _port;
    private void OpenSocket()
    {
        var endPoint = new DnsEndPoint(_ipAddress, _port);
        SocketAsyncEventArgs args = new SocketAsyncEventArgs();
        args.UserToken = new ClientUserToken(null, "foo");
        args.RemoteEndPoint = endPoint;
        args.Completed += OnSocketCompleted;
        _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _clientSocket.ConnectAsync(args);
    }
    void OnSocketCompleted(object sender, SocketAsyncEventArgs e)
    {
        switch (e.LastOperation)
        {
            case SocketAsyncOperation.Connect: ProcessConnect(e); break;
            case SocketAsyncOperation.Receive: ProcessReceive(e); break;
            case SocketAsyncOperation.Send: ProcessSend(e); break; // this never gets called
        }
    }
    void ProcessConnect(SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success)
        {
            byte[] response = new byte[1024];
            e.SetBuffer(response, 0, response.Length);
            _clientSocket.ReceiveAsync(e);
        }
    }
    void ProcessReceive(SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success && e.BytesTransferred > 0)
        {
            var userToken = e.UserToken as ClientUserToken; // this token is always the one set in ProcessConnect
            // process the data
            if (!_clientSocket.ReceiveAsync(e))
            {
                ProcessReceive(e);
            }
        }
    }
    // this is never called, for some reason
    void ProcessSend(SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success)
        {
            var userToken = e.UserToken as ClientUserToken;
            if (!_clientSocket.ReceiveAsync(e))
            {
                ProcessReceive(e);
            }
        }
    }
    // this is the public API that users use to actually send data across
    public void SendToServer(byte[] data, int len, Handler handler)
    {
        SocketAsyncEventArgs args = new SocketAsyncEventArgs();
        args.UserToken = new ClientUserToken(handler, "bar");
        args.SetBuffer(data, 0, len);
        if (!_clientSocket.SendAsync(args))
        {
            ProcessReceive(args);
        }
    }
}

正如上面的注释所建议的,在ProcessReceive中,userToken。测试总是"foo"和userToken。处理程序总是空的。

到目前为止,我还不能进入ProcessSend,所以我看不到它实际发送的SocketAsyncEventArgs。有人知道为什么这个事件没有被触发(发送后完成)吗?我搞砸了我的SendToServer函数吗?

我意识到可能存在同步等其他问题,但我不认为这是这里的问题。我尝试过的一件事是设置一个ManualResetEvent,以确保在连接完成之前没有人向服务器发送数据(ProcessConnect),但这也没有解决问题。

任何帮助将不胜感激!

EDIT:所以发生这种情况的原因是因为当我在ProcessConnect函数中调用ReceiveAsync时,当服务器为我的数据发回响应时,它正在使用。因此,UserToken"foo"出现在处理程序中。下一次服务器发送数据时,ReceiveAsync使用UserToken"bar"的参数。所以它有点不同步,对于双工通信位。我不能确保我从客户端发送的SocketAsyncEventArgs与响应上使用的SocketAsyncEventArgs是相同的。似乎唯一的解决方案是让SL客户端打开两个套接字——一个用于服务器发起的数据,另一个用于客户端发起的请求。但是,这意味着我没有利用双工特性。

SocketAsyncEventArgs.UserToken未被更新

这个模型不起作用,因为我在每次发送时都创建了一个新的SocketAsyncEventArgs,这意味着数据可以通过这些参数中的任何一个返回。我一直在向SocketAsyncEventArgs池模型移动,每个客户端一次只能有一个请求/响应。