我正在尝试编写一个异步套接字服务器/客户端,但我不断收到以下错误:
Unable to read data from the transport connection: A blocking operation was interrupted
    by a call to WSACancelBlockingCall.
Inner Exception: System.Net.Sockets.SocketException (0x80004005): A blocking operation
    was interrupted by a call to WSACancelBlockingCall
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size,
    SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
它在我的 SockerServer 类中在以下行中引发了此异常:
BytesRead = ClientStream.Read(MessageBuffer, 0, BufferSize);
这只发生在客户端尝试与服务器断开连接时 - 他们似乎断开连接正常,然后我得到这个异常。
这是代码:
消息处理程序
客户端中有一个此类的实例,服务器中的每个客户端都有一个实例。这用于为每个客户端包装 NetworkStream,以便可以将消息写入其中。
public class MessageHandler
{
    private readonly ASCIIEncoding ByteEncoder = new ASCIIEncoding();
    private readonly NetworkStream ClientStream;
    public MessageHandler(NetworkStream Stream)
    {
        this.ClientStream = Stream;
    }
    public void Send(byte[] Message)
    {
        ClientStream.Write(Message, 0, Message.Length);
        ClientStream.Flush();
    }
    public void Send(string Message)
    {
        byte[] MessageBytes = ByteEncoder.GetBytes(Message);
        ClientStream.Write(MessageBytes, 0, MessageBytes.Length);
        ClientStream.Flush();
    }
}
MessageHandlerEventArgs
public class MessageHandlerEventArgs : EventArgs
{
    public readonly MessageHandler SocketMessage;
    public MessageHandlerEventArgs(MessageHandler Messages)
    {
        this.SocketMessage = Messages;
    }
}
SocketHandler(SocketServer 和 SocketClient 的基类)
public abstract class SocketHandler
{
    protected const int DefaultPort = 3000;
    protected const int BufferSize = 4096;
    protected readonly Action<byte[]> MessageAction;
    public SocketHandler(Action<byte[]> MessageAction)
    {
        this.MessageAction = MessageAction;
        ClientConnected += OnClientConnected;
        ClientDisconnected += OnClientDisconnected;
    }
    protected void HandleConnection(IAsyncResult ar)
    {
        TcpClient Client = (TcpClient)ar.AsyncState;
        ThreadPool.QueueUserWorkItem((x) => HandleConnection(Client));
    }
    protected void HandleConnection(TcpClient NetworkClient)
    {
        try
        {
            using (NetworkStream ClientStream = NetworkClient.GetStream())
            {
                MessageHandler Messages = new MessageHandler(ClientStream);
                DoClientConnected(new MessageHandlerEventArgs(Messages));
                byte[] MessageBuffer = new byte[BufferSize];
                int BytesRead;
                while (true)
                {
                    BytesRead = 0;
                    BytesRead = ClientStream.Read(MessageBuffer, 0, BufferSize);
                    if (BytesRead == 0)
                    {
                        DoClientDisconnected(new MessageHandlerEventArgs(Messages));
                        break;
                    }
                    else
                    {
                        MessageAction.Invoke(MessageBuffer.ToArray());
                    }
                }
                NetworkClient.Close();
            }
        }
        catch (Exception ex)
        {
            Logger.ExceptionLog.AddEntry(ex, "SocketHandler.HandleConnection");
        }
    }
    protected abstract void OnClientConnected(object sender, MessageHandlerEventArgs e);
    protected abstract void OnClientDisconnected(object sender, MessageHandlerEventArgs e);
    public event EventHandler<MessageHandlerEventArgs> ClientConnected;
    protected void DoClientConnected(MessageHandlerEventArgs args)
    {
        if (ClientConnected != null)
        {
            ClientConnected(this, args);
        }
    }
    public event EventHandler<MessageHandlerEventArgs> ClientDisconnected;
    protected void DoClientDisconnected(MessageHandlerEventArgs args)
    {
        if (ClientDisconnected != null)
        {
            OnClientDisconnected(this, args);
        }
    }
    public event EventHandler StatusChanged;
    protected void DoStatusChanged()
    {
        if (StatusChanged != null)
        {
            StatusChanged(this, EventArgs.Empty);
        }
    }
}
套接字服务器
public class SocketServer : SocketHandler
{
    private static List<MessageHandler> CurrentClients = new List<MessageHandler>();
    private ServerStatus _Status;
    public ServerStatus Status
    {
        get { return _Status; }
        private set
        {
            _Status = value;
            DoStatusChanged();
        }
    }
    private readonly TcpListener NetworkServer;
    public SocketServer(Action<byte[]> MessageAction)
        : base(MessageAction)
    {
        NetworkServer = new TcpListener(IPAddress.Any, DefaultPort);
    }
    public void Start()
    {
        try
        {
            if (Status == ServerStatus.Stopped)
            {
                ThreadPool.QueueUserWorkItem((x) => ListenForClient());
                Status = ServerStatus.Started;
            }
        }
        catch (Exception ex)
        {
            Logger.ExceptionLog.AddEntry(ex, "SocketServer.Start");
        }
    }
    public void Stop()
    {
        try
        {
            if (Status != ServerStatus.Stopped)
            {
                Status = ServerStatus.Stopped;
                NetworkServer.Stop();
            }
        }
        catch (Exception ex)
        {
            Logger.ExceptionLog.AddEntry(ex, "SocketServer.Stop");
        }
    }
    private void ListenForClient()
    {
        try
        {
            Status = ServerStatus.WaitingClient;
            NetworkServer.Start();
            while (Status != ServerStatus.Stopped)
            {
                if (!NetworkServer.Pending())
                {
                    Thread.Sleep(100);
                    continue;
                }
                else
                {
                    TcpClient NetworkClient = NetworkServer.AcceptTcpClient();
                    ThreadPool.QueueUserWorkItem((x) => HandleConnection(NetworkClient));
                    Status = ServerStatus.Connected;
                }
            }
        }
        catch (Exception ex)
        {
            Logger.ExceptionLog.AddEntry(ex, "SocketServer.ListenForClient");
        }
    }
    protected override void OnClientConnected(object sender, MessageHandlerEventArgs e)
    {
        CurrentClients.Add(e.SocketMessage);
    }
    protected override void OnClientDisconnected(object sender, MessageHandlerEventArgs e)
    {
        CurrentClients.Remove(e.SocketMessage);
        Status = (CurrentClients.Count == 0)
            ? ServerStatus.WaitingClient
            : ServerStatus.Connected;
    }
}
套接字客户端
public class SocketClient : SocketHandler
{
    private ClientStatus _Status;
    public ClientStatus Status
    {
        get { return _Status; }
        set
        {
            _Status = value;
            DoStatusChanged();
        }
    }
    private TcpClient NetworkClient;
    public MessageHandler Messages;
    public SocketClient(Action<byte[]> MessageAction)
        : base(MessageAction)
    {
        NetworkClient = new TcpClient();
    }
    public void Connect(IPAddress ServerAddress, int ServerPort)
    {
        try
        {
            if (Status == ClientStatus.Disconnected)
            {
                Status = ClientStatus.Connecting;
                NetworkClient.Connect(ServerAddress, ServerPort);
                ThreadPool.QueueUserWorkItem((x) => HandleConnection(NetworkClient));
            }
        }
        catch (Exception ex)
        {
            Logger.ExceptionLog.AddEntry(ex, "SocketClient.Connect");
        }
    }
    public void Disconnect()
    {
        try
        {
            if (Status != ClientStatus.Disconnected)
            {
                Status = ClientStatus.Disconnecting;
                NetworkClient.Close();
                Status = ClientStatus.Disconnected;
            }
        }
        catch (Exception ex)
        {
            Logger.ExceptionLog.AddEntry(ex, "SocketClient.Disconnect");
        }
    }
    protected override void OnClientConnected(object sender, MessageHandlerEventArgs e)
    {
        Messages = e.SocketMessage;
        Status = ClientStatus.Connected;
    }
    protected override void OnClientDisconnected(object sender, MessageHandlerEventArgs e)
    {
        Messages = null;
        Status = ClientStatus.Disconnected;
    }
}