많은 동시 연결을 허용하는 서버 데몬을 만들고 클라이언트가 서버로 데이터를 전송합니다. 현재 각 클라이언트 연결을 새 스레드로 생성하고 있습니다. 나는 (정확히는) 세분화 오류를 포함하여 다양한 문제를 야기하는 기존 연결의 ID를 때로는 (항상은 아님) 돌려 줄 것이라고보고있다.accept는 기존 연결을 반환하여 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()
으로이 문제를 경험 한 적이 없으므로 아마도 threading과 관련된 문제입니까? 이 시점에서, 나는 생각할 수있는 모든 것에 대해서만 시도해 보았습니다. 그러나 나는 방금 무언가를 놓친 것 같습니다.
편집 : 편집 된 코드는 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
}
}
확인해야 할 것이 하나 있는데 올바르게 바인딩 했습니까? – shinkou
예, 다시 확인했습니다. 'bind()'가 올바르게 발생합니다. 그렇지 않으면 연결을 허용하기 전에 프로그램을 종료합니다. – cegfault
실제 코드를 게시하십시오. 잘못된 코드가 있습니다. 특히'test'는 포인터이지만'test.conid'를 사용합니다. 또는 최소한 문제를 나타내는 _compilable 및 runnable_ 프로그램으로 압축하십시오. – paxdiablo