我想在套接字处于活动状态时不断收到并同时从不同的线程调用send方法(对不起我的英文)。
我考虑过以下几点:
由于会有多个客户端,我认为如果操作系统负责生成线程以免损害性能会更好,因此,我不想在循环中检查Receive方法在每个客户端的不同线程上。我立即放弃了。
为了避免创建实现每次调用BeginReceive时使用的IAsyncResult接口的类型的实例,因此不会对GB施加压力,并且在IO操作负载过重时具有更好的性能我决定不使用BeginReceive / EndReceive。
相反,我考虑过为每个连接使用ReceiveAsync方法和可重用的SocketAsyncEventArgs实例。例如,如果服务器支持1000个连接,则它将具有相同数量的SocketAsyncEventArgs实例,在连接处于活动状态期间,每个客户端一个实例。当客户端断开底层SocketAsyncEventArgs时,实例将返回池以供以后在另一个连接中使用(解决方案选择)
关于发送操作,我不关心发送请求是否按呼叫顺序处理;重要的是字节不与其他消息的字节混合,因此在远程主机的接收缓冲区中,消息一个接一个地到达,以便负责协议的类可以解释它们。 / p>
为此,我不想调用BeginSend / EndSend,因为除了在每次调用中创建不同的IAsynResult实例之外,我理解在从不同的线程调用时,消息字节可能是混合的,这是正确的?我不记得很久以前我在哪里读过它。我想有可靠的消息来源。无论是否真实,我都不打算使用它。
我也理解SendAsync就像是BeginSend / EndSend的掩码,不同之处在于它重用了底层的IAsyncResult实例。这让我觉得虽然我可以同时调用SendAsyn方法和BeginSend,但也有可能在输出缓冲区中混合字节。
要使用SendAsyn处理多个调用,您还应该在每次调用时提供不同的SocketAsyncEventArgs实例,这是我不喜欢的。然后我考虑使用Semaphore类来保证一次发送操作,一旦完成,重用上一次发送操作中使用的SocketAsyncEventArgs实例。这样我每个连接只会占用两个SocketAsyncEventArgs实例(一个接收,一个接收),我避免使用这些对象的池,不仅如此,它还可以防止不同消息的字节在输出中混合缓冲液中。
关于我发现不断收到的解决方案,我很满意。但对于运输业务,我不确定。使用SendAsync时,我没有发现任何优势。我只想要多个线程可以同时调用送货方式。然后我考虑使用Send方法并将其包装在异步方法中,如下所示:
public virtual async Task<int> SendAsync(byte[] buffer, int offset, int size, CancellationToken cancellationToken)
{
ThrowIfDisposed();
var sendingRequest = CancellationTokenSource.CreateLinkedTokenSource(requests.Token, cancellationToken);
int bytesSent = 0;
try
{
await semaphore.WaitAsync(sendingRequest.Token).ConfigureAwait();
while(bytesSent < size)
{
int bytesWrote = clientSocket.Send(buffer, offset, size, SocketFlags.None);
if(bytesWrote == 0)
{
throw new SocketException((int)SocketError.NotConnected);
}
else
{
bytesSend += bytesWrote;
}
}
}
catch(SocketException)
{
Disconnect();
throw;
}
finally
{
semaphore.Release();
sendingRequest.Dispose();
sendingRequest = null;
}
return bytesSent;
}
如果你告诉我上面说的所有内容我错了,或者我的方法是否正确,或者如何改进我已有的内容,我将不胜感激。
感谢。