我正在c中创建一个服务器守护程序,它接受大量的同时连接,并且客户端将发送数据到服务器。我目前有每个客户端连接被催生成一个新的线程。我看到accept()
有时(并不总是)会返回现有连接的ID(显然)会导致各种各样的问题,包括分段错误。接受返回现有连接,导致seg错误
我甚至关闭了插座选项SO_REUSEADDR
以确保不是这种情况。每当一个客户端连续进行多次调用时,一切正常(我的代码中的conid
递增 - 5,6,7,8,9等等)。但是,每当有多个客户关系同时连接时,有时候conid
会被重复(来自一次运行的示例:5,6,7,7,8,9,10,10,10,11,12,12,...) 。
我在想如何accept()
可以返回现有的连接?如果我在多个线程中调用accept()
会很有意义,但正如您在下面看到的,它只存在于主进程线程中。另一方面,我从来没有遇到这个问题select()
,所以也许这是一个线程问题?在这一点上,我尝试了所有我能想到的东西,但对我来说显然我只是缺少了一些东西
编辑:编辑代码以显示mystruct未被释放while循环,并(希望)提供更多的见解。
编辑#2:每个请求,我已经发布了我的示例的完整源代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdarg.h>
#include <time.h>
#include <errno.h>
#include <netdb.h>
//this is my test structure
struct mystruct_ {
int id; //only id for testing
};
typedef struct mystruct_ mystruct;
//error logging function
void merr(const char *msg, ...) {
//get the time
time_t t;
time(&t);
//grab this function's arguments
va_list args;
char buf[BUFSIZ];
va_start(args,msg);
//build the message
vsprintf(buf,msg,args);
//output the message
printf(" ERROR :: %s\n",buf);
//that's it!
va_end(args);
}
//this function handles the threads
void *ThreadedFunction(void *arg) {
//get the passed structure
mystruct *test = (mystruct *)arg;
//print conid -- this is where I am seeing the duplicates
printf("my connection id is %d\n",test->id);
// do some stuff, like: pull vars out of mystruct
int nbytes;
char buf[256];
while(1) {
if((nbytes=recv(test->id, buf, sizeof buf, 0)) <= 0) {
//handle break in connection
close(test->id);
} else {
//for this example, just print out data from client to make my point
buf[nbytes] = 0;
printf("%s",buf);
}
}
}
//main just sets up the connections and creates threads
int main(int argc, char *argv[])
{
char *port = "1234";
//get ready for connection
struct sockaddr_storage addr;
socklen_t addrsize = sizeof addr;
struct addrinfo hints, *res, *ai, *p;
int sockfd, conid, rv;
int yes = 1;
//
//load up address structs with getaddrinfo():
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
if((rv = getaddrinfo(NULL, port, &hints, &ai))!= 0) {
merr("failed to bind port '%s': %s\n",port,gai_strerror(rv));
exit(1);
}
//
//bind the port
for(p=ai; p!=NULL; p=p->ai_next) {
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if(sockfd<0) continue;
//setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); //commented for testing
if(bind(sockfd,p->ai_addr,p->ai_addrlen)<0) { close(sockfd); continue; }
break;
}
//if we don't have p, it means server didn't get bound
if(p==NULL) { merr("failed to bind port '%s' (reason unknown)",port); exit(2); }
freeaddrinfo(ai); //all done with this
//
// listen to the (now bounded) socket:
if(listen(sockfd,10)==-1) { merr("listen; errmsg: \"%s\"",strerror(errno)); exit(3); }
// bind(), listen(), etc... blah blah blah
mystruct test[1024]; //just for testing
printf("Ready and Listening...\n");
while(1) {
conid = accept(sockfd, (struct sockaddr *)&addr, &addrsize);//get a connection
test[conid].id = conid;
pthread_t p;
pthread_create(&p,NULL,ThreadedFunction,&test[conid]); //create new thread
}
}
有一件事要检查是否正确bind()? – shinkou 2011-12-22 04:05:13
是的,我仔细检查。 'bind()'正确发生。如果没有,我在接受连接之前退出程序 – cegfault 2011-12-22 05:21:01
请发布真实代码,你有什么不正确的,特别是'test'是一个指针,但你使用'test.conid'。或者至少将其归结为展示问题的最低_compilable和runnable_程序。 – paxdiablo 2011-12-22 05:32:06