我正在构建一个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#


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


N次,启动分离的工作线程


每个线程应打开一个发送套接字,然后通过TCP 12345将一些数据发送到127.0.0.1
发送后,线程应立即终止



这应该是孩子的游戏。我想使用大量的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#


如上面的输出所示,服务器收到了四个测试消息。

太好了…这里发生了很多奇怪的事。这些“ THREAD X STARTED”消息必须存在一些错误,因为看起来线程0、1和6从未启动,而线程3、7和9两次启动了。但是numThreads == 10且启动了十个线程,因此我暂时将忽略该问题。

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

更奇怪的是,Errno代码是“成功”。如果成功...为什么通话失败?我觉得我确实缺少一些非常明显的东西。

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

我已经使用Google搜索了大约三个小时,但没有收集任何有用的信息。任何建议或意见将不胜感激。

最佳答案

问题在这里:

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

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


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

关于c - C::线程不一致地打开发送套接字,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58000555/

10-17 02:29