2012-01-17 3 views
0

블로킹 소켓 서버를 비 블로킹 버전으로 다시 쓰는 데 문제가 있습니다. 사실, 나는 소켓을 더 이상 연결하지 못하는 것 같아요, 나는 오늘의 대부분을 인터넷 검색하고, 내가 여기 저기에있는 다른 해결책을 시도했지만, 아무도 제대로 작동하지 않는 것 같습니다 ... 현재 내 서버 루프는 새로운 소켓을 수락하지 않고 select() 호출 시간 초과를 유지합니다. 클라이언트 소켓이 어떤 수준에서 연결하는 것 같습니다. 시작하면 쓰기를 차단하고 서버를 닫으면 연결이 피어에 의해 재설정되었음을 알립니다.* nix & C++ 비 블로킹 소켓 서버 작성하기

올바른 가정은 다음과 같습니까? 비 블로킹 서버의 경우 일반적으로 소켓을 열고 비 블로킹 플래그를 설정하고 바인드하고 읽기 파일 설명자를 호출하기 시작한 다음 채워지기를 기다려야합니까? 끝내 대기중인 이전 차단 "accept()"호출을 제거해야합니다. 수락 호출을 시도하면 지금 -1이됩니다 ...

다음은 내가 시도하는 관련 코드입니다. 당신은 전체 루프를 표시하지 않기 때문에 지금

fd_set incoming_sockets; 
.... 
int listener_socket, newsockfd, portno; 
socklen_t clilen; 
struct sockaddr_in serv_addr, cli_addr; 
.... 
listener_socket = socket(AF_INET, SOCK_STREAM, 0); //get socket handle 
int flags = fcntl(listener_socket, F_GETFL, 0); 
if(fcntl(listener_socket, F_SETFL, flags | O_NONBLOCK) < 0) 
    log_writer->write_to_error_log("Error setting listening socket to non blocking", false); 
memset(&serv_addr, 0, sizeof(struct sockaddr_in)); 

serv_addr.sin_family = AF_INET; 
serv_addr.sin_addr.s_addr = INADDR_ANY; 
serv_addr.sin_port = htons(portno); 
.... 
if (bind(listener_socket, (struct sockaddr *) &serv_addr, 
     sizeof(struct sockaddr_in)) < 0) 
{ 
    log_writer->write_to_error_log("Unable to bind socket, aborting!", true); 
} 
.... 
struct timeval timeout; 
timeout.tv_sec = 1; 
timeout.tv_usec = 0; 

int ready_sockets = 0; 

listen(listener_socket,1); 

FD_ZERO(&incoming_sockets); 
FD_SET(listener_socket, &incoming_sockets); 

while(true) 
{ 

ready_sockets = select(listener_socket + 1 , &incoming_sockets, (fd_set *) 0, (fd_set *) 0, &timeout ); 

if(ready_sockets == 0) 
    { 
     //I loop here now for ever 
     std::cout << "no new sockets available, snooze 2\n"; 
     sleep(2); 
    } else 
    { 
    std::cout << "connection received!\n"; 
+0

오류에 대해서는'select'의 반환 값을 실제로 확인해야합니다. 지금 당장은 문제가되지 않을 수도 있지만 장래에있을 수 있습니다. 그 외에는 코드에서 명백한 오류를 볼 수 없습니다. –

+0

안녕하세요, 요아킴, 답장을 보내 주셔서 감사합니다! 실제로 다른 값도 확인합니다 (0보다 작은 경우).하지만 지금은 == 0으로 유지하고 있기 때문에 가독성을 위해 생략했습니다. – julumme

답변

1

, 나중에 그것을 모르겠어요,하지만 당신은 select 모든 호출하기 전에 기술자 세트와 타임 아웃 구조를 초기화해야한다.

+0

아! 실제로 트릭을하는 것처럼 보였습니다! 사실 while 루프 밖에있는 파일 설명자를 초기화 했으므로 이제 클라이언트를 연결할 수있었습니다. – julumme

0

당신은 FD_ZERO() FD_SET()를 매크로 내부 루프 이주자한다, 선택하게됩니다 실제로 변화 fd_sets의 비트 마스크 (시간 초과 값). 반복 할 때마다 다시 초기화하십시오. 또한 -1을 반환하는 select 및 관련 errno (EPIPE ...)를 확인하십시오.

while(true) 
{ 

FD_ZERO(&incoming_sockets); 
FD_SET(listener_socket, &incoming_sockets); 



ready_sockets = select(listener_socket + 1 , &incoming_sockets, (fd_set *) 0, (fd_set *) 0, &timeout ); 

if(ready_sockets == 0) 
    { 
     ... } 
+0

요아킴이 알아챈 것과 똑같은 해결 방법이었습니다. – julumme