CentOS for C ++应用程序突然收到缓冲区建立

时间:2015-06-15 12:25:26

标签: c++ linux sockets centos udp

在CentOS上接收UDP数据时,我有一个奇怪的问题。当我的应用程序收到数据时,一切都很好,并且所有数据包都按预期接收,然后突然内核接收缓冲区(net.core.rmem)开始填满没有明显的原因,直到它满了,数据包被丢弃。奇怪的是,即使发送方以与以前相同的速率发送,缓冲区或多或少是空的,直到它开始急剧增加。好像我没有考虑的资源耗尽,或者操作系统改变专用于接收操作的线程的优先级。 receive()仍然接收和读取数据,但缓冲区开始填充太快。

文件从发送应用程序发送到接收应用程序。在发送和接收应用程序之间有一个单向网关,因此不可能有拥塞控制(或TCP)。只有当我发送一个大文件(大约3 GiB或更多)时才会出现问题。当我发送多个小文件时,一切正常,即使它们的大小总和远大于3 GiB。

目前我无法进一步指出问题,而且我对可能出现的问题感到震惊。这是关于系统配置的信息,我可以想象它是相关的,但我已经研究了内存泄漏,磁盘使用情况和缓冲区大小,而无法找到特定的东西。

  • 数据以100 Mbit / s的速率发送。
  • 发送和接收机器上的MTU均为9000。
  • net.core.rmem_max / net.core.rmem_default设置为536870912字节(巨大)。
  • net.core.netdev_max_backlog设置为65536(巨大)。
  • 发送的每个UDP数据包为8192字节,不包括UDP标头。
  • 通过tmpfile()创建的临时文件用于存储每个文件的数据。
  • 文件完成后立即关闭临时文件(验证了hashsum)。
  • 接收文件时的CPU使用率一致为100%。
  • 接收文件时的内存使用率一致为0.5%。

接收()

std::vector<uint8_t>* vector = new std::vector<uint8_t>();

while (signal == 0)
{
  ret = _serverio->Receive(*vector);
  if (ret == -1 || ret == 0)
  {
    continue;
  }
  else
  {
    Produce(vector);
    vector = new std::vector<uint8_t>();
  }
}

_serverio-&gt;接收(std :: vector&amp; data)

ssize_t n;
data.resize(UDPMAXMSG);
int res = m_fdwait.Wait(m_timeoutms);
if(res < 1) {
  data.resize(0);
  return res; // timeout or interrupt
}

n = read(m_servfd, &(data[0]), data.size());
if(n < 0) {
  if(errno == EINTR) {
    data.resize(0);
    return -1;
  }
  else {
    throw socket_error(errno, "UDPServer::Receive");
  }
}
data.resize(n);
return n;

制作(std :: vector * vector)

_producerSemaphore.aquire();
_queue.lock();
_buffer.push_back(vector);
_queue.unlock();
_consumerSemaphore.release();

消费()

bool aquired = false;
while (!aquired)
{
  if (_terminated)
  {
    // Consume should return NULL immediately if
    // receiver has been terminated.
    return NULL;
  }

  aquired = _consumerSemaphore.aquire_timeout(1);
}

std::vector<uint8_t>* vector = NULL;
_queue.lock();
vector = _buffer.front();
_buffer.pop_front();
_queue.unlock();
_producerSemaphore.release();

return vector;

recv_buffer.sh(用于监控接收缓冲区)

while true ; do
  _BUFFER_VALUE=$(printf "%d" "0x$(grep 2710 /proc/net/udp \
    | awk '{print $5}' | sed 's/.*://')")
  _DELTA=$(expr $_BUFFER_VALUE - $_PRE_BUFFER)
  _PRE_BUFFER=$_BUFFER_VALUE
  echo "$_BUFFER_VALUE : $_DELTA"
  sleep 0.1
done

recv_buffer.sh输出

buffer-size delta
0 0
0 0
...
10792 10792
10792 0
0 -10792
10792 10792
0 -10792
0 0
0 0
0 0 // This type of pattern goes on for 2.5 GiB
...
0 0
0 0
0 0
0 0
971280 971280 // At this point the buffer starts to fill
1823848 852568
1931768 107920
2039688 107920
2179984 140296
2287904 107920
2406616 118712
2525328 118712
2644040 118712
2741168 97128
2881464 140296
3010968 129504
3140472 129504
...
533567272 647520
536038640 2471368
536675368 636728
536880416 205048 // At this point packets are dropped
536869624 -10792
536880416 10792
536880416 0
536869624 -10792
536880416 10792
536869624 -10792
536880416 10792
536880416 0
536880416 0
536880416 0
536880416 0
536880416 0

0 个答案:

没有答案