C :: 线程不一致地打开发送套接字

C :: Threads Inconsistently Open a Sending Socket

我正在构建一个 C 程序,我正在与一个奇怪的 - 不一致的 - 线程和套接字错误搏斗 gethostbyname() 我以前从未见过。

首先是一些环境方面的东西:我正在开发一个 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#

objective 这里:我开发了另一个 C 程序,我希望它有一天会成为网络服务。服务器工作正常,但我需要对其进行压力测试。所以我构建了一个客户端程序来用模拟的网络请求轰炸它。服务器启动并侦听 TCP 12345 后,客户端程序只需执行以下操作:

这应该是儿戏。我想用大量的 N 看看当我的服务器被攻击时会发生什么。

让我向您介绍我的代码,然后描述问题。该程序相对简单。有一些结构,然后是 main()。基本上,main() 循环 N = numThreads,每次都创建一个分离的工作线程。每个线程都有一个填充的 package 结构,其中包含稍后将使用的信息:

typedef struct{
   int sock;
   struct sockaddr address;
   int addr_len;
} connection_t;

typedef struct{
   char* IP;
   int port, myNum;
} package;


void process(void* pack);                  // code for the thread, see below...


int main( int argc, char ** argv ){
   pthread_t  thread;
   int        numThreads = 10;             // or 100 or 1000 or whatever
   char       svrIP[20] = "127.0.0.1";
   int        portNumber = 12345;

   int i=0;
   for( ; i<numThreads; i++){

      package* pack   = (package*) malloc( sizeof(package) );
      pack->IP        = (char*) malloc( sizeof(char) * 20 );
      strcpy( pack->IP, svrIP );
      pack->port      = portNumber;
      pack->myNum     = i;

      pthread_create(&thread, NULL, process, (void*) pack);
      pthread_detach(thread);

      free( pack->IP );
      free( pack );
   }

   sleep(1);

   printf("END OF PROGRAM\n");
   return 0;
}

无论我为 numThreads 设置什么,上面的一切都很好用。现在是线程的代码。出生时,线程会尝试打开一个套接字,然后发送一个文本字符串。然后线程终止。请注意所有 fprintf() 围绕 gethostbyname() 的代码——我稍后会提到它:

void process(void* pack){
   int                  len, sock = -1;
   struct sockaddr_in   address;
   struct hostent *     host;

   char* msg = "Some text string here for the server...";

   printf("THREAD %d STARTED:  %s  --  %d\n", ((package*)pack)->myNum, ((package*)pack)->IP, ((package*)pack)->port );

   // create the socket
   sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (sock <= 0){
      fprintf( stderr, "Thread %d: error: cannot create socket\n", ((package*)pack)->myNum );
      pthread_exit(0);
   }

   // connect to server
   address.sin_family = AF_INET;
   address.sin_port = htons( ((package*)pack)->port );
   host = gethostbyname( ((package*)pack)->IP );
   if (!host){
      fprintf( stderr, "Thread %d: error: unknown host %s  --  Error is:  (%d) \”%s\”\n",
            ((package*)pack)->myNum,
            ((package*)pack)->IP,
            errno, strerror(errno));
      pthread_exit(0);
   }

   memcpy(&address.sin_addr, host->h_addr_list[0], host->h_length);
   if (connect(sock, (struct sockaddr *)&address, sizeof(address))){
      fprintf( stderr, "Thread %d: error: cannot connect to host %s\n", ((package*)pack)->myNum, ((package*)pack)->IP );
      pthread_exit(0);
   }

   printf("Thread %d: Sending message \”%s\”\n", ((package*)pack)->myNum, msg);

   len = strlen(msg);
   write(sock, &len, sizeof(int));
   write(sock, msg, len);

   printf("Thread %d: message sent, exiting...\n", ((package*)pack)->myNum );

   close(sock);

   pthread_exit(0);
}

好的,这就是代码。那么问题来了:

无论我为 numThreads 设置什么值,一些工作线程成功打开套接字,而一些则没有。失败的是对 gethostbyname() 的调用失败。查看以下内容;我已将 numThreads 设置为 10,这意味着我应该看到线程 0 到 9 启动:

me@ubuntu:/home/me/socketProject# ./runTest
THREAD 2 STARTED:  127.0.0.1  --  24601
THREAD 5 STARTED:  127.0.0.1  --  24601
THREAD 3 STARTED:  127.0.0.1  --  24601
THREAD 3 STARTED:  127.0.0.1  --  24601
THREAD 4 STARTED:  127.0.0.1  --  24601
THREAD 7 STARTED:  127.0.0.1  --  24601
Thread 7: Sending message "Some text string here for the server..."
Thread 7: message sent, exiting...
THREAD 7 STARTED:  127.0.0.1  --  24601
Thread 7: Sending message "Some text string here for the server..."
Thread 7: message sent, exiting...
THREAD 8 STARTED:  127.0.0.1  --  24601
Thread 8: Sending message "Some text string here for the server..."
Thread 8: message sent, exiting...
THREAD 9 STARTED:    --  24601
THREAD 9 STARTED:    --  24601
Thread 9: Sending message "Some text string here for the server..."
Thread 9: message sent, exiting...
Thread 9: error: unknown host   --  Error is:  (0) "Success"
Thread 9: error: unknown host   --  Error is:  (0) "Success"
Thread 9: error: unknown host   --  Error is:  (0) "Success"
Thread 9: error: unknown host   --  Error is:  (0) "Success"
Thread 9: error: unknown host   --  Error is:  (0) "Success"
Thread 9: error: unknown host   --  Error is:  (0) "Success"
END OF PROGRAM
me@ubuntu:/home/me/socketProject#

如以上输出所示,服务器收到了四条测试消息。

Sooooooooo…这里发生了很多奇怪的事情。那些“THREAD X STARTED”消息肯定有一些错误,因为看起来线程 0、1 和 6 从未启动过,而线程 3、7 和 9 不知何故启动了两次。但是 numThreads == 10 并且启动了 10 个线程,所以我暂时忽略这个问题。

更令人担忧的是,六个线程在调用 gethostbyname() 时失败了。我承认:对于这段代码,我从教科书中复制了一个示例,但我不记得是从哪里得到的。但我想知道 if(!host) 声明是否有意义。我在非线程版本中测试时没有问题,但现在…

更奇怪的是 Errno 代码是 "Success." 如果成功...为什么调用失败?我觉得我错过了一些非常非常明显的东西。

同样困扰我的是这个问题不一致。有时当我测试这个时,7/10 线程成功发送。有时是 1/10。我的平均成功率约为 3/10。如果我对 C 有所了解,那么不一致的问题通常表明一个变量已成功创建但未初始化。这里可能需要初始化什么? host 结构?我不确定。

我已经用谷歌搜索了大约三个小时,但没有找到任何有用的东西。任何建议或意见将不胜感激。

问题在这里:

  pthread_create(&thread, NULL, process, (void*) pack);
  pthread_detach(thread);

  free( pack->IP );
  free( pack );

...您为新线程 (pack) 创建了一个特定的资源,然后在该线程完成其工作之前立即将其删除!这些对 free 的调用应该在 process

结束时执行