【问题标题】:Prevent Thread From Sleeping When Calling Socket.Receive调用 Socket.Receive 时防止线程休眠
【发布时间】:2012-01-15 19:46:11
【问题描述】:

我正在开发一个通过套接字接收 tcp 数据的低延迟金融应用程序。
这就是我建立套接字连接和接收字节的方式:

public class IncomingData
{
  Socket _Socket;
  byte[] buffer = new byte[4096];

  public static void Connect(IPEndPoint endPoint)
  {
    _Socket = new Socket(
                  AddressFamily.InterNetwork,
                  SocketType.Stream, 
                  ProtocolType.Tcp);

    _Socket.Connect(endPoint);
  }

  public static void ReadSocket(int ReadQty)
  {
    _Socket.Receive(buffer, 0, ReadQty, SocketFlags.None); 
  }
}

我听说当你在 Stream 套接字上调用 Receive() 时,调用线程被置于休眠状态,并在接收到数据时被唤醒。我希望线程全速运行(使用 CPU 容量)。

有没有办法使用 Stream 套接字来做到这一点?如果唯一的方法是使用原始套接字,您能否提供一个示例?

【问题讨论】:

  • 在没有数据的情况下将线程置于睡眠模式,从资源管理的角度来看,实际上是一件好事。我不太明白你充分利用 CPU 容量的观点。如果数据还没有,你期望 CPU 运行什么?只是一个空循环不断轮询数据?
  • 是的,我想做一个持续轮询数据的 while 循环。基本上这样一个线程就不必花费任何时间来唤醒。
  • 这完成了完全相反的,线程将耗尽它的量子并且暂时不会被调度。它显着增加了延迟。
  • 您想要超快但您使用的是 TCP?丢包时会发生什么? TCP 会阻塞所有传入的数据,直到重传成功。

标签: c# sockets networking raw-sockets low-latency


【解决方案1】:

如果我理解正确,您希望 Receive 不被阻止吗?

看看socket类的BeginX/EndX方法。这些方法异步执行(不在当前线程上阻塞)。它们接受一个回调方法作为它们的参数之一,并且该方法将在操作完成时调用(在这种情况下,将接收数据)。它本质上与事件相同。

public class IncomingData
{
    Socket _Socket;
    byte[] buffer = new byte[4096];

    public static void Connect(IPEndPoint endPoint)
    {
        _Socket = new Socket(
                      AddressFamily.InterNetwork,
                      SocketType.Stream, 
                      ProtocolType.Tcp);        

        _Socket.Connect(endPoint);

    }

    public static void ReadSocket(int ReadQty)
    {
         // Wait for some data to be received. When data is received,
         // ReceiveCallback will be called.
         _Socket.BeginReceive(buffer, 0, ReadQty, SocketFlags.None, ReceiveCallback, null);
    }

    private static void ReceiveCallback(IAsyncResult asyncResult)
    {
        int bytesTransferred = _Socket.EndReceive(asyncResult);

        // ...
        // process the data
        // ...
    }
}

【讨论】:

  • 使用 BeginReceive() 调用 ReceiveCallBack() 是通过线程池进行的,对吗?我需要控制正在运行的线程数,而线程池的延迟对于这个应用程序来说太不可靠了。
【解决方案2】:

您可以使用Socket.Poll 来确定套接字是否有数据,否则继续旋转:

// will spin here until poll returns true
while(!socket.Poll(0, SelectMode.SelectRead));
socket.Receive...

【讨论】:

  • @FuzzyLogic:好的,测试一下并告诉我们。
【解决方案3】:

也许可以通过查看networkComms.net 来解决通过网络发送数据的整个问题,特别是演示最基本功能的简短示例here,希望不会过于复杂!您可能遇到的大多数问题都已经解决了,这可能会为您节省一些时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-25
    • 2015-06-27
    • 2014-12-27
    • 2013-05-24
    相关资源
    最近更新 更多