C 线程不一致地打开发送套接字
我正在构建一个C程序,我正在努力解决gethostbyname的一个奇怪的、不一致的线程和套接字错误,这是我以前从未见过的 首先是一些环境方面的东西:我正在开发一个Ubuntu box,我的代码是用GCC编译的:C 线程不一致地打开发送套接字,c,multithreading,sockets,gethostbyname,C,Multithreading,Sockets,Gethostbyname,我正在构建一个C程序,我正在努力解决gethostbyname的一个奇怪的、不一致的线程和套接字错误,这是我以前从未见过的 首先是一些环境方面的东西:我正在开发一个Ubuntu box,我的代码是用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#
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来看看当我的服务器受到重击时会发生什么
让我带您浏览我的代码,然后描述问题。程序相对简单。有几个结构,然后是主结构。基本上,N=numThreads的主循环每次都创建一个分离的工作线程。每个线程都有一个填充的包结构,其中包含稍后将使用的信息:
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设置了什么值,有些工作线程成功地打开了套接字,有些则没有。失败的是调用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”(线程X启动)消息中肯定有一些错误,因为看起来线程0、1和6从未启动过,而线程3、7和9不知何故启动了两次。但是numThreads==10,并且10个线程已经启动,所以现在我将忽略这个问题
更令人担忧的是,有六个线程调用gethostbyname失败。我承认:对于这段代码,我从教科书中复制了一个示例,我不记得从哪里得到的。但我想知道如果!host语句是有意义的。当我在非线程版本中测试时没有问题,但是现在
更奇怪的是,错误代码就是成功。如果它成功了。。。为什么通话失败了?我觉得我错过了一些非常非常明显的东西
这个问题前后矛盾,这也让我感到困扰。有时,当我测试这个时,7/10线程成功地发送。有时十分之一的人会这样做。我的平均成功率约为3/10。如果我对C有所了解的话,那就是不一致的问题通常表明变量已经成功创建,但尚未初始化。这里可能需要初始化什么?主机结构?我不确定
我已经在谷歌上搜索了大约三个小时,但是没有找到任何有用的东西。如有任何建议,我们将不胜感激 问题在于:
pthread_create(&thread, NULL, process, (void*) pack);
pthread_detach(thread);
free( pack->IP );
free( pack );
。。。您可以为新的线程包创建特定的资源,然后在线程完成其工作之前立即将其删除!这些免费呼叫应在流程结束时执行查看此问题的答案:。这看起来确实是一个线程安全问题。还要检查手册页中的gethostbyname;它不会在错误上设置errno,而是设置h_errno。@MarkA嘿Mark-天哪,你的评论非常有用!我不知道gethostbyname存在全局内存问题。为了使用getaddrinfo,我不得不花几个小时重新安装代码,但这是值得的。感谢上帝你发现了这一点;如果您想使用多线程网络编程,这样的问题似乎很关键。为什么这些信息不在教程的前端和中心?伙计,如果你不插嘴,我会很痛苦的。接得好,非常感谢。我欠你一杯啤酒。@Pete gethostbyname已被弃用,你应该改用getaddrinfo。@RemyLebeau谢谢Remy。我为我的代码配备了getaddrinfo,现在它运行得越来越流畅。gethostbyname造成的破坏肯定比我想象的要大哇,谢谢Darren!你是100%正确的。我永远也不会明白这一点。我已经习惯于在调用malloc的同一个函数中将我的调用与free配对,所以我在这里没有考虑就这么做了。太棒了,谢谢你的帮助!
pthread_create(&thread, NULL, process, (void*) pack);
pthread_detach(thread);
free( pack->IP );
free( pack );