0

非同期ソケットサーバー/クライアントを作成しようとしていますが、次のエラーが発生し続けます。

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

このクラスのインスタンスはクライアントに1つあり、サーバーのクライアントごとに1つあります。これは、メッセージを書き込むことができるように、各クライアントの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;
    }
}
4

1 に答える 1

1

そのようにコーディングしないでください。スレッド/スレッドプールの使用は間違っています。Socket/TcpClient には、使用する必要がある非同期メソッドがあります

使用できるフレームワークを作成しました。すべての処理を処理します。受信/送信データを処理するだけです。

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

于 2012-05-22T08:22:48.813 に答える