2016-09-21 8 views
0

여러 원격 프로세스를 동기화하기 위해 소켓을 사용하고 있습니다.연결이 끊어져서 소켓 연결이 거부되었습니다.

아이디어는 프로세스가 그냥 그런, 서버 측을 관리하는의 pthread를 생성하는 것입니다 :

void *listener(void * in) { 
    int sockfd; 
    socklen_t clilen; 
    struct sockaddr_in serv_addr, cli_addr; 
    int n = *((int *) in); 

    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    if (sockfd < 0) 
     error("ERROR opening socket"); 

    int option = 1; 
    setsockopt(sockfd, SOL_SOCKET, (SO_REUSEPORT | SO_REUSEADDR), (char*) &option, sizeof (option)); 
    bzero((char *) &serv_addr, sizeof (serv_addr)); 
    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = INADDR_ANY; 
    serv_addr.sin_port = htons(PORT); 

    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) 
     error("ERROR on binding"); 

    if (listen(sockfd, n) < 0) 
     error("ERROR when listening"); 

    clilen = sizeof (cli_addr); 
    int cnt = 0; 
    while (cnt < n) { 
     int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); 
     if (newsockfd < 0) { 
      error("ERROR on accept"); 
     } 
     cnt++; 
    } 
    close(sockfd); 
    return 0; 
} 

한편, 다른 프로세스가 실행됩니다 :

int sockfd; 
struct sockaddr_in serv_addr; 
struct hostent *server; 

sockfd = socket(AF_INET, SOCK_STREAM, 0); 
if (sockfd < 0) 
    error("ERROR opening socket"); 

server = gethostbyname(_managementHost); //managementHost); 
if (server == NULL) 
    error("ERROR, no such host\n"); 

bzero((char *) &serv_addr, sizeof (serv_addr)); 
serv_addr.sin_family = AF_INET; 
bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length); 
serv_addr.sin_port = htons(PORT); 

if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) 
    error("ERROR connection"); 

close(sockfd); 

을 이제 문제를 I 내가 서버에 동시에 연결하려고하는 많은 프로세스를 가지고있을 때, 그들 중 일부는 연결을 거부했습니다. 오류가 발생했습니다.

받아 들일 준비가되지 않았기 때문일 것입니다 ... 사실, 나는 그것이 일어날 수 있다는 것을 읽었지만 나의 특별한 경우는 발견하지 못했습니다.

누구든지 문제를 해결할 수 있습니까?

내게 가능한 해결책은 각 수락에 대한 스레드를 만드는 것입니다.하지만이를 피하는 것이 좋습니다.

감사합니다.

EDIT : 수정 된 서버의 소켓 이중 초기화. @Remy Lebeau 덕분에.

+0

나는 당신이하려고하는 것을 충분히 잘 이해하지 못한다고 생각합니다. 연결을 수락하고 누설함으로써 성취해야하는 것은 무엇입니까? 이 중 어떤 것이 동기화를 생성합니까? 또는 동기화 및 비 리소스 누출 목표를 유발하는 중요한 비트를 잘라 냈습니까? –

+0

아이디어는 다른 프로세스가 주어진 지점에 도달 할 때까지 첫 번째 프로세스가'pthread_join'을 기다릴 것이라는 아이디어입니다. 나는 그것들을 동기화하기 위해서만 소켓을 사용하며, 프로세스를 의사 소통하는 것에는 관심이 없다. – siserte

답변

1

이제 문제는 서버에 동시에 연결하려고하는 많은 프로세스가 있는데 그 중 일부는 연결 거부 오류를 던지고있는 것입니다.

대기중인 TCP 소켓에는 연결 대기 중 백 로그가 있습니다. listen()의 두 번째 매개 변수는 수락되기 전에 백 로그 대기열에 허용되는 연결 수를 지정합니다. 새로운 클라이언트가 백 로그가 꽉 찼을 때 연결을 시도하면 클라이언트가 거부됩니다. 클라이언트 나 서버가 할 수있는 일은 아무것도 없습니다. 오류를 감지하고 나중에 다시 연결하는 것은 고객의 책임입니다.

listener()은 지정된 연결 수에 도달 할 때까지 클라이언트를 수락하지만 수신 대기열 대기열 크기에도 동일한 수를 사용합니다. 활성 연결 수와 보류 연결 수는 두 가지입니다. 많은 고객이 동시에 연결할 것으로 예상되는 경우 거절 오류를 피하기 위해 큰 백 로그 크기가 필요합니다. 하지만 그 백로 그는 예상 트래픽에 비례하여 크기가 지정되어야합니다. 1000 개의 클라이언트가 있지만 한 번에 20 개만 연결하는 경우 백 로그를 1000이 아닌 25로 설정하십시오.

listener()에 다른 논리 버그가 있습니다. socket()을 두 번 호출하고 두 개의 소켓을 동일한 sockfd 변수에 저장하므로 첫 번째 소켓이 누출됩니다. 두 번째 전화는 socket() (즉 setsockopt() 앞에있는 번호)을 삭제해야합니다. accept()가 반환하는 소켓도 새고 있습니다. 사용 후 소켓을 close()으로 받아 들여야합니다.

+0

그래서 프로세스가 연결되고 'accept()'가 아직 발행되지 않았더라도, 클라이언트 연결은 백 로그에 남아있을 것입니다. 맞습니까? 버그에 관해서는, 당신이 맞습니다. 너무 많은'socket()'호출이 있습니다. 그러나, 하나의 소켓 만 열었 기 때문에'accept()'이후에 소켓을 닫을 수 없다. (listener()를 수행하는 하나의 쓰레드이다.)'accept()'마다 쓰레드를 만들어야 하는가? . – siserte

+0

@SergioIserte 예, accept()에 의해 제거 될 때까지 연결은 백 로그에 남아 있습니다. 한 번에 여러 클라이언트에 서비스를 제공하려는 경우 허용 된 클라이언트마다 새 스레드/프로세스를 만들어야합니다 (호출 당 'accept()'자체), 그렇지 않으면 소켓에 블로킹을하지 않고'select()'/'epoll()'을 사용하여 스레드에서 다중 클라이언트를 다중화하면된다. –

+0

죄송합니다. _accepted client_와 무슨 뜻인지 잘 모르겠습니다. 내가 추천 한 것은'accept()'를 호출하는'n' 스레드를 만드는 것이 었습니다. – siserte

0

각 클라이언트에 대해 하위를 생성하기 위해 fork를 호출하여 서버를 동시 실행하십시오. 그것을하는 쉬운 방법, IMO. 스레딩을 피하고 연결 거부 오류를 중지합니다.

EDIT : 서버를 사전 포킹 할 수도 있습니다. 비록 당신이 전혀 잠그고 있다면, 당신은 받아들이는 것 주위에 잠그기를 어떻게 처리 할 것인지 연구해야 할 것입니다.

+0

가능한 경우 새로운 프로세스를 포킹하지 않겠습니다 ... – siserte

관련 문제