2010-10-01 130 views
2

我想优化TCP套接字包装物,有很多的入站连接的挣扎。我在一个基本的聊天服务器和一个小客户端应用程序中测试它,以便将客户端发送给它。这两个应用程序都位于由千兆交换机连接的单独的W2k3服务器上。Socket.SendAsync服用几秒钟完成

通过试验和错误,我改进我的测试,以10个客户在100周毫秒的时间间隔连接,那么一旦所有10个连接它们每一个发送达到100MS间隔“入室”消息给服务器,再一次。当服务器收到一条消息时,它会向房间中的每个人列表回复发件人,并向房间中的其他人发送消息,告诉他们新的到来。

每个发送都需要1秒钟才能完成(这对于100多个客户端来说会持续3-4秒),并且通过日志记录,我已经确定延迟在Socket.SendAync和相应的事件发生之间。整个Cpu使用率始终很低。

我用尽了一切我能想到的,并花了几天寻找线索在线和我在一个完全丧失。这不可能是正常的吗?

编辑:代码按要求。我已经整理了一下,删除了不相关的计数器和日志记录等,现在它已经在黑客攻击之上破解了,因为我试图缩小这个问题的范围。

private void DoSend(AsyncUserToken token, String msg) 
    { 
     SocketAsyncEventArgs writeEventArgs = new SocketAsyncEventArgs(); 
     writeEventArgs.Completed += ProcessSend; 
     writeEventArgs.UserToken = token; 
     Byte[] sendBuffer = Encoding.UTF8.GetBytes(msg + LineTerminator); 
     writeEventArgs.SetBuffer(sendBuffer, 0, sendBuffer.Length); 

     Interlocked.Add(ref m_totalBytesAttemptedSend, sendBuffer.Length); 
     Logger2.log(Logger2.Debug5, token.ConnectionId, "Total Bytes attempted: " + m_totalBytesAttemptedSend); 

     bool willRaiseEvent = true; 
     try 
     { 
      willRaiseEvent = token.Socket.SendAsync(writeEventArgs); 
     } 
     catch (Exception e) 
     { 
      Logger2.log(Logger2.Debug2, token.ConnectionId, e.Message); 
      writeEventArgs.Dispose(); 
     } 
     if (!willRaiseEvent) 
     { 
      ProcessSend(null, writeEventArgs); 
     } 
    } 


    private void ProcessSend(Object sender, SocketAsyncEventArgs e) 
    { 
     AsyncUserToken token = (AsyncUserToken)e.UserToken; 
     Logger2.log(Logger2.Debug5, token.ConnectionId, "Send Complete"); 
     if (e.SocketError == SocketError.Success) 
     { 
      Interlocked.Add(ref m_totalBytesSent, e.BytesTransferred); 
      Logger2.log(Logger2.Debug5, ((AsyncUserToken)e.UserToken).ConnectionId, "Total Bytes sent: " + m_totalBytesSent); 

     } 
     else 
     { 
      if (token.Connected) 
      { 
       CloseClientSocket(token); 
      } 
     } 
     e.Dispose(); 
    } 
+0

你能发表一些相关的代码吗?猜测套接字问题是非常困难的。 – 2010-10-01 16:37:40

+0

你有一个SocketAsyncEventArgs池吗? – 2010-10-01 19:59:28

+0

埃里克 - 我目前没有汇集SocketAysncEventArgs,但计划稍后添加。不过,我在创建SocketAysncEventArgs并填充其缓冲区并将结束时间记录为回调中的第一个操作之后记录了开始时间,因此,虽然我知道它的低效率,但它不应该影响此部分执行? – Adster 2010-10-04 09:24:44

回答

1

您在每个连接上发送了多少数据,并且您发送速度有多快?

通常是异步发送需要很长的时间才能完成的原因是,你填写的TCP窗口(见here了解详细信息)和本地TCP堆栈无法发送任何数据,直到它得到一些的ACK从对等。如果您继续发送数据,那么您只是在网络子系统中本地排队,因为堆栈不允许发送它。由于拥塞和数据包丢失,这可能会变得更糟,因为传输中的数据需要更长的时间才能到达对端,并且ACK需要更长的时间才能恢复...

如果是这种情况(以及诸如WireShark之​​类的工具应该使您能够看到窗口大小更新和零窗口情况等),那么增加连接的窗口大小可能会有所帮助(请参阅here)。

如果协议中没有明确的流量控制,则上述情况更可能发生。最好在协议设计中包含某种形式的显式流量控制,恕我直言,以避免这种情况。

这也是明智的包括一些这方面的发送端的保护作为一个无界的发送者可以通过内存非常迅速咀嚼。我使用过的一种方法很好用,就是有一个队列,可以将出站数据放入队列中,并根据先前发送的发送完成情况实际发送此队列中的数据(请参阅here)。

+0

感谢Len,我会安装wireshark以查看它是否会散发出任何光。同时,我已经读取了第一次发送完成时(在我打电话给SendAsync后1.2-1.3秒)传输的数据的一些读数,并且它确实数量很小,所以我不相信这是问题所在。 成功发送的总字节数:40(1发送) 收到的总字节数:827(10收到) 尝试发送的总字节数:250(4发送) – Adster 2010-10-04 09:13:27

+0

嗯,听起来不像是问题所在。这通常在发送大量数据时显示 – 2010-10-04 10:16:55

1

尝试使用socket.NoDelay=True;。 默认值为No这意味着基础堆栈会在实际发送之前尝试累积传输。