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