LoginSignup
8
10

More than 5 years have passed since last update.

UDPで3Gbpsくらいのデータを常時受信する場合(WinSock)

Posted at

10GbE NICで3Gbpsくらいの常時データをUDPで受信する事があったので、
その際に必要だったことについてまとめた。

 1.ノンブロッキングソケットに設定する
 2.受信バッファの拡張
 3.ドライバ側のパラメータ設定
 4.スレッドのプライオリティを高くする

ノンブロッキングソケットに設定する

ブロッキングソケットで受信する場合、以下のように連続受信すると、recvfromでほぼ毎回(多くの場合、パケットバッファは空なので)、スレッドがパケット到着まで待機状態になる。そのため、オーバヘッドが大きくなり、パケットを取りこぼすことがあるようだ。

while(1){
   len = recvfrom(...); //パケットを受信
   if(len!=sizeof(buf)){
     continue; //パケットがなかった場合
   }
   copy_pkt(...);//パケットを保存
}

ノンブロッキングソケットで受信すれば、基本的にrecvfromでスレッドが待機状態にならないので、パケット取りこぼしがなくなった。
*その代り、CPU負荷は高くなった。

ioctlsocketでブロッキング/ノンブロッキングを切り替え可能
以下MSDNのサンプル抜粋
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms738573(v=vs.85).aspx

u_long iMode = 1; //iMode==0:blocking, iMode!=0:non-blocking
int iResult = ioctlsocket(m_socket, FIONBIO, &iMode);
if (iResult != NO_ERROR)
  printf("ioctlsocket failed with error: %ld\n", iResult);
  }

受信バッファの拡張

受信バッファが少ないと、OSによるスレッド切り替えが行われて受信できない間に、バッファが溢れる可能性が高くなるため、setsocketoptでネットワーク受信バッファを拡張する。

    int buffSize = (1024 * 1024) * 512; //512MB
    ret = ::setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (const char *)&buffSize, sizeof(int));
    if (ret != 0) {
        TRACE(_T("割り当て失敗")); 
    }

ドライバ側パラメータ設定

NICのパラメータを調整する。
ネットワークアダプタを右クリックして、起動したダイアログの構成ボタンをクリックする。
さらにダイアログが起動するので、詳細設定タブを選択すると、受信バッファ等の値を変更できるので、受信バッファを最大にする。

スレッドのプライオリティを高くする。

受信スレッドを、THREAD_PRIORITY_HIGHEST等に設定して,OSにより実行中にスレッドを切り替えられにくくする。

8
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
10