异步套接字客户端/服务器抛出异常(TcpClient& TcpListener)

时间:2012-05-22 05:07:35

标签: sockets c#-4.0 asynchronous

我正在尝试编写异步套接字服务器/客户端,但我不断收到以下错误:

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);

仅当客户端尝试与服务器断开连接时才会出现这种情况 - 它们似乎断开连接正常,然后我收到此异常。

这是codez:

的MessageHandler

客户端中有一个此类的实例,服务器中的每个客户端都有一个实例。这用于为每个客户端包装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;
    }
}

SocketClient

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;
    }
}

1 个答案:

答案 0 :(得分:1)

不要那样编码。使用线程/线程池是错误的。 Socket / TcpClient具有应该使用的异步方法

我已经创建了一个可以使用的框架。它会为您处理所有处理。您需要做的就是处理传入/传出数据。

http://blog.gauffin.org/2012/05/griffin-networking-a-somewhat-performant-networking-library-for-net/