您好,我正在.NetCore上开发一个非常简单的套接字服务器。该服务器必须允许多个客户端并在不取消的情况下开始从它们读取数据。
这是它的代码:
public class ClientHandler
{
public ClientHandler(Socket workSocket, int bufferSize)
{
WorkSocket = workSocket;
BufferSize = bufferSize;
receiveBuffer = new byte[BufferSize];
currentBuffer = new byte[0];
}
public Socket WorkSocket { get; }
// Size of receive buffer.
public int BufferSize { get; }
// Receive buffer.
public byte[] receiveBuffer { get; set; }
// Received data.
public byte[] currentBuffer { get; set; }
}
public class MyServer
{
public MyServer(string ipAddress, int port,
IProtocolParser parser, CancellationToken token, ILogger logger)
{
_ipAddress = ipAddress;
_port = port;
InternalCts = new CancellationTokenSource();
_token = InternalCts.Token;
_parser = parser;
_logger = logger.ForContext(GetType());
}
private const int BUFFER_SIZE = 1024;
private readonly IProtocolParser _parser;
private readonly ILogger _logger;
private readonly int _port;
private readonly string _ipAddress;
private readonly CancellationToken _token;
private readonly ManualResetEvent _allDone = new ManualResetEvent(false);
private CancellationTokenSource InternalCts { get; set; }
private Socket Server { get; set; }
public void Start()
{
try
{
var ipAddress = IPAddress.Parse(_ipAddress);
var endpoint = new IPEndPoint(ipAddress, _port);
_logger.Debug("Creating Socket Server On {ipAddress}:{port}", _ipAddress, _port);
Server = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Server.Bind(endpoint);
Server.Listen(10);
while(!_token.IsCancellationRequested)
{
_allDone.Reset();
_logger.Debug("Waiting For Client");
Server.BeginAccept(AcceptCallback, Server);
_logger.Debug("Waiting One!");
_allDone.WaitOne();
_logger.Debug("Begin Accept Finished");
}
_logger.Debug("Task Finished!");
return;
}
catch (Exception e)
{
_logger.Error("error");
}
}
private void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
_allDone.Set();
// Get the socket that handles the client request.
var listener = (Socket)ar.AsyncState;
var handler = listener.EndAccept(ar);
// Create the state object.
var client = new ClientHandler(handler, BUFFER_SIZE);
handler.BeginReceive(client.receiveBuffer, 0, client.BufferSize, 0,
new AsyncCallback(ReadCallback), client);
}
private void ReadCallback(IAsyncResult ar)
{
// Retrieve the state object and the handler socket
// from the asynchronous state object.
var client = (ClientHandler)ar.AsyncState;
var handler = client.WorkSocket;
// Read data from the client socket.
var bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
client.currentBuffer = ArrayExtensions.Combine(
client.currentBuffer, client.receiveBuffer.SubArray(0, bytesRead));
var (message, newBuffer) = _parser.UnpackMessage(client.currentBuffer);
if (!string.IsNullOrEmpty(message))
{
_logger.Debug("New Message Received: {message}", message);
}
client.currentBuffer = newBuffer;
}
if (!_token.IsCancellationRequested)
{
// Not all data received. Get more.
handler.BeginReceive(client.receiveBuffer, 0, client.BufferSize, 0,
new AsyncCallback(ReadCallback), client);
}
}
public void Stop()
{
InternalCts.Cancel();
_logger.Debug("Stopping Server...");
_logger.Debug("Closing Socket...");
Server.Close();
_allDone.Set();
_logger.Debug("Socket Closed!");
}
}
这是主程序:
static void Main(string[] args)
{
var parser = new VenomOEMProtocolParser();
var cts = new CancellationTokenSource();
var logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.Enrich.FromLogContext()
.Enrich.WithThreadId()
.WriteTo.Console().CreateLogger();
var venomOem = new VenomOEM("192.168.0.107", 100, parser, cts.Token, logger);
AppDomain.CurrentDomain.ProcessExit += (s, e) =>
{
venomOem.Stop();
};
Console.CancelKeyPress += delegate
{
venomOem.Stop();
};
try
{
venomOem.Start();
logger.Debug("FINISHED!");
}
catch (OperationCanceledException oce)
{
logger.Debug(oce, "Operation Canceled Exception");
}
catch (Exception e)
{
logger.Error(e, "Unexpected Exception!");
}
}
如您所见,当在控制台应用程序上按Ctrl + C键并且执行了stop方法时,我启动了服务器并停止了它,但是以某种方式应用程序冻结并且没有关闭。我认为这与重置事件有关,但找不到问题。
有什么建议吗?
谢谢!