【发布时间】:2021-08-20 07:02:34
【问题描述】:
我有一个 TCPListener 服务器在专用端口上侦听,并且只有一个客户端与服务器连接。客户端与服务器建立连接,并以 60 秒的间隔继续发送心跳消息以保持其存活。此外,它发送不同类型的请求消息(每个消息的前 4 个字节为消息大小保留),服务器接收这些消息并将套接字传递给 Task(异步),该任务执行包括 DB I/O 在内的漫长过程并使用相同的套接字返回响应。它一直工作正常,但最近客户端已经开始异步发送 1000 个请求。服务器以良好的速度响应初始请求,但在处理了大约 100 个请求后,响应变得缓慢。我征求您的专家意见,以使响应更加有力。
class ServerA
{
.......
.......
private void StartServer()
{
......
socket = tcpListener.AcceptSocket();
Process(socket);
.......
}
private void Process(Socket clientSocket)
{
while(true)
{
byte[] msg = new byte[1024 * 1024];
int totalMsgLength = clientSocket.Receive(msg);
ClientRequest req = new ClientRequest();
byte[] request = new byte[totalMsgLength];
Buffer.BlockCopy(msg, 0, request, 0, totalMsgLength);
req.HandleRequest(clientSocket, request);
}
}
}
class ClientRequest
{
byte[] request;
Socket clientSocket;
public void HandleRequest(Socket clientSocket,byte[] request)
{
try
{
this.request = request;
this.clientSocket = clientSocket;
Task.Run(() =>
{
Entertain(null);
});
}
catch (Exception ex)
{
.....
}
}
private void Entertain(object callback)
{
request = admin.PerformAction(ref request); //Long process
clientSocket.Send(request);
}
}
【问题讨论】:
-
附带说明:您没有保护
clientSocket.Send免受并发写入,这很糟糕 -
感谢您的专家意见;根据您的建议,如何避免这种不良做法?
-
因为您使用的是同步写入:
lock (clientSocket) { clientSocket.Send(request); } -
你觉得有必要吗?每次都从“ClientRequest”类的新对象调用 Entertain() 方法,所以我相信它已经是线程安全的。
-
@jdweng re chunks:我在回答中提出了同样的担忧,但(见评论)显然这只是来自简化代码;另外:参见“巨型帧”——每个数据包可以得到比 1500 字节大得多的数据
标签: c# sockets tcplistener