【问题标题】:C Programming :: accept() works and then doesn't, in stress-testingC Programming :: accept() 在压力测试中有效,然后无效
【发布时间】:2019-09-17 20:07:48
【问题描述】:

我正在编写我认为是一个简单的 C 套接字程序的代码。该代码将充当原始服务器。它需要创建一个监听socket,然后每次联系到它都需要accept()传入的连接,然后再分出一个线程来处理一些基本的处理。线程和处理部分我或多或少可以工作,但是 accept() 部分在代码成功处理一些初始连接后发生故障。这是一个问题,因为我预计这个程序将需要连续运行,并且可能必须处理大量传入请求。

首先是一些环境方面的东西:我正在开发一个 Ubuntu 机器,我的代码是用 GCC 编译的:

root@ubuntu:/home/me/socketProject# gcc -v
...
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)
root@ubuntu:/home/me/socketProject#

我的 ma​​in() 函数设置了一个监听套接字,然后开始一个无限循环。对于每个进入的连接,它都会尝试 accept(),然后将工作传递给一个分离的线程:

int main(int argc, char ** argv)
{
   int             sock = -1;
   struct          sockaddr_in address;
   int             port = 12345;
   connection_t*   connection;
   pthread_t       thread;

   // Create the listening socket
   sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (sock <= 0){
      fprintf(stderr, "%s: error: cannot create socket\n", argv[0]);
      return -3;
   }

   // Bind socket to port
   address.sin_family = AF_INET;
   address.sin_addr.s_addr = INADDR_ANY;
   address.sin_port = htons(port);
   if (bind(sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) < 0){
      fprintf(stderr, "%s: error: cannot bind socket to port %d\n", argv[0], port);
      return -4;
   }

   // Listen on the port
   if (listen(sock, 5) < 0){
      fprintf(stderr, "%s: error: cannot listen on port\n", argv[0]);
      return -5;
   }

   // Listen forever...
   while (1){
      // Accept incoming connections
      connection = (connection_t *)malloc(sizeof(connection_t));

      printf("1)  [[ sock: %d -- address: %s -- addr_len: %d ]]\n", connection->sock, &connection->address.sa_data, connection->addr_len );

      connection->sock = accept(sock, &connection->address, &connection->addr_len);

      printf("2)  [[ sock: %d -- address: %s -- addr_len: %d ]]\n", connection->sock, &connection->address.sa_data, connection->addr_len );

      if (connection->sock <= 0){
         printf(" *** PROBLEM!!!  Value of errno: %d\n ", errno);
         free(connection);
      }
      else{
         // Start a new thread but do not wait for it
         pthread_create(&thread, 0, process, (void *)connection);  // process() omitted
         pthread_detach(thread);
      }
   }
   return 0;
}

相当教科书的东西。当只有一个传入连接时,我制定了所有逻辑并让一切正常运行。

但随后我开始进行压力测试,并立即意识到我遇到了问题。我编写了一个客户端程序,它连续发送 X 个测试请求。上面的服务器代码可以很好地处理一些初始请求,但随后就崩溃了。这是输出:

root@ubuntu:/home/me/socketProject# ./server
        *** 1)  [[ sock: 18954128 -- address:  -- addr_len: 0 ]]
        *** 2)  [[ sock: 7 -- address:  -- addr_len: 16 ]]
        *** 1)  [[ sock: 18970816 -- address:  -- addr_len: 0 ]]
        *** 2)  [[ sock: 8 -- address:  -- addr_len: 16 ]]
        *** 1)  [[ sock: 18962080 -- address:  -- addr_len: 0 ]]
        *** 2)  [[ sock: 9 -- address:  -- addr_len: 16 ]]
        *** 1)  [[ sock: 18962112 -- address:  -- addr_len: 0 ]]
        *** 2)  [[ sock: 10 -- address:  -- addr_len: 16 ]]
        *** 1)  [[ sock: 18954064 -- address:  -- addr_len: 0 ]]
        *** 2)  [[ sock: 11 -- address:  -- addr_len: 16 ]]
        *** 1)  [[ sock: 18954160 -- address:  -- addr_len: 0 ]]
        *** 2)  [[ sock: 12 -- address:  -- addr_len: 16 ]]
        *** 1)  [[ sock: 18907120 -- address:  -- addr_len: 0 ]]
        *** 2)  [[ sock: 13 -- address:  -- addr_len: 16 ]]
        *** 1)  [[ sock: 18950880 -- address:  -- addr_len: 0 ]]
        *** 2)  [[ sock: 14 -- address:  -- addr_len: 16 ]]
        *** 1)  [[ sock: 18961856 -- address:  -- addr_len: 0 ]]
        *** 2)  [[ sock: 15 -- address:  -- addr_len: 16 ]]
        *** 1)  [[ sock: 18957136 -- address:  -- addr_len: 0 ]]
        *** 2)  [[ sock: 17 -- address:  -- addr_len: 16 ]]
        *** 1)  [[ sock: 18957168 -- address:  -- addr_len: -518793662 ]]
        *** 2)  [[ sock: -1 -- address:  -- addr_len: -518793662 ]]
 *** PROBLEM!!!  Value of errno: 22
        *** 1)  [[ sock: 18961856 -- address:  -- addr_len: -518793662 ]]
        *** 2)  [[ sock: -1 -- address:  -- addr_len: -518793662 ]]
 *** PROBLEM!!!  Value of errno: 22
        *** 1)  [[ sock: 18961856 -- address:  -- addr_len: -518793662 ]]
        *** 2)  [[ sock: -1 -- address:  -- addr_len: -518793662 ]]
 *** PROBLEM!!!  Value of errno: 22
        *** 1)  [[ sock: 18961856 -- address:  -- addr_len: -518793662 ]]
        *** 2)  [[ sock: -1 -- address:  -- addr_len: -518793662 ]]
 *** PROBLEM!!!  Value of errno: 22
        *** 1)  [[ sock: 18961856 -- address:  -- addr_len: -518793662 ]]
        *** 2)  [[ sock: -1 -- address:  -- addr_len: -518793662 ]]
 *** PROBLEM!!!  Value of errno: 22
        *** 1)  [[ sock: 18961856 -- address:  -- addr_len: -518793662 ]]
        *** 2)  [[ sock: -1 -- address:  -- addr_len: -518793662 ]]
 *** PROBLEM!!!  Value of errno: 22
        *** 1)  [[ sock: 18961856 -- address:  -- addr_len: -518793662 ]]
        *** 2)  [[ sock: -1 -- address:  -- addr_len: -518793662 ]]
 *** PROBLEM!!!  Value of errno: 22
        *** 1)  [[ sock: 18961856 -- address:  -- addr_len: -518793662 ]]
        *** 2)  [[ sock: -1 -- address:  -- addr_len: -518793662 ]]
 *** PROBLEM!!!  Value of errno: 22
        *** 1)  [[ sock: 18961856 -- address:  -- addr_len: -518793662 ]]
        *** 2)  [[ sock: -1 -- address:  -- addr_len: -518793662 ]]
 *** PROBLEM!!!  Value of errno: 22
        *** 1)  [[ sock: 18961856 -- address:  -- addr_len: -518793662 ]]
        *** 2)  [[ sock: -1 -- address:  -- addr_len: -518793662 ]]
 *** PROBLEM!!!  Value of errno: 22
        *** 1)  [[ sock: 18961856 -- address:  -- addr_len: -518793662 ]]

你看到了问题。在上面的示例中,大约十次成功请求后发生了一些事情,然后 accept() 开始抱怨 ERRNO 22。快速的 Google 搜索显示 ERRNO 22 是“EINVAL: Invalid argument”,这显然不好。

我从学生时代就做过一些简单的套接字编程,但我以前从未遇到过 accept() 的问题。我真的很困惑。在我看来,N-1 个请求到达并由 accept() 成功处理。但随后出现第 N 个,accept() 不喜欢它,并且套接字被破坏。如何或为什么,我不知道。

accept() 抱怨“无效参数”。但是客户端实际上是一遍又一遍地发送完全相同的测试消息。 N-1 个连接如何提供有效参数,但第 N、N+1、N+2... 个参数无效?这让我大吃一惊。

一些观察:

  • 这是一种黑白现象。我的意思是 套接字在 100% 的时间里都能正常工作,但随后出现了问题 accept() 发生,然后套接字再也无法工作。

  • 我进行了很多测试,但不知道有多少成功 当我开始一个新的测试时,我会得到连接。我有多达88个 在套接字停止工作之前成功连接。在另一个 测试,在套接字消失之前我只有 2 个成功的连接 仰卧起坐。之前的平均成功连接数 套接字中断时间约为 17。

  • 我的客户端测试程序不会尝试将请求间隔 发送;它只是打开一个套接字并开始轰炸我的服务器 以最快的速度编程。我这样做是因为我想进行压力测试。 但也许我的客户端程序发送测试请求太快了 服务器要跟上……?

  • 我想,也有可能是客户端程序导致 问题。我不这么认为,因为它只是发送相同的测试 一遍又一遍的消息,它永远不会引发错误。

有人见过这样的问题吗?我已经在 SO 上寻找了大约一个小时,但我找不到另一篇 accept() 有效的帖子,然后又无效了。

感谢任何帮助/建议。

【问题讨论】:

  • 旁注:不要以 root 身份运行您的东西...使用用户帐户。
  • @DanielJour 是的,这很好。很好的收获,一定会做到的。 :)

标签: c sockets stress-testing


【解决方案1】:

您需要将addr_len 初始化为addr 的大小。

如果您查看手册页是否接受,则在列出的errno 值下; EINVAL 如果addrlen 无效(例如是否定的)

(大惊小怪):这不是同一个论点。

您正在调用malloc(),这可能会返回未初始化的内存。

无论您将addrlen 设置为多少字节的地址可以复制到地址中; 0 表示没有。

【讨论】:

  • 对于那些关注这个帖子的人:我添加了“connection->addr_len = 20;”在 malloc()'ing 连接结构之后立即作为一行。现在套接字像冠军一样保持稳定。
  • 非常感谢 mevets!
猜你喜欢
  • 2018-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-24
  • 2012-06-30
相关资源
最近更新 更多