非同期ソケットサーバー/クライアントを作成しようとしていますが、次のエラーが発生し続けます。
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;
}
}