2012-06-13 1 views
0

나는 clients과 연결되어있는 SOCKET 2 개의 연결을 가진 server을 가지고 있으며,이 메시지를 보내거나받을 때 멈추지 않는 비 차단 모드 인 server을 설정합니다. 나는 각 연결의 SOCKET 시간을 설정하려면,하지만 난 다음 코드를 사용하는 경우 :비 차단 모드 서버의 클라이언트로부터 메시지를 수신하는 시간 제한을 설정하는 방법은 무엇입니까?

void getMessage(SOCKET connectedSocket, int time){ 
    string error = R_ERROR; 
    // Using select in winsock 
    fd_set set; 
    timeval tm; 

    FD_ZERO(&set); 
    FD_SET(connectedSocket, &set); 

    tm.tv_sec = time; // time 
    tm.tv_usec = 0; // 0 millis 
    switch (select(connectedSocket, &set, 0, 0, &tm)) 
    { 
    case 0: 
     // timeout 
     this->disconnect(); 
     break; 
    case 1: 
     // Can recieve some data here 
     return this->recvMessage(); 
     break; 
    default: 
     // error - handle appropriately. 
     break; 
    } 
return error; 
} 

내 서버가 없습니다 더 이상 모드 것도 차단하지 않습니다! 두 번째 연결에서 메시지를 가져 오는 첫 번째 연결 종료 시간까지 기다려야합니다! 그건 내가 기대하는 것이 아니야! 그럼, 비 블로킹 모드에서 타임 아웃을 설정하는 방법이 있습니까? 아니면 직접 처리해야합니까?

+1

두 소켓 모두에서'select'를하도록 코드를 리팩토링해야 할 수도 있습니다. 그리고'select'가 어떤 소켓이 준비되어 있는지 체크 아웃하지 않는다면 (둘 다 가능함을 기억하십시오) 적절한 receive 메소드를 호출하십시오 . 요아킴이 한 말에 +1 –

+0

+1. 핵심 서버 루프는 모든 소켓에서 select()를 호출해야하며 각 소켓과 연관된 객체 (클래스 인스턴스)를가집니다. 각 클래스 인스턴스의 "Read"메소드는 각 소켓에서 가능한 한 많이 읽고 처리 할 수있는 것을 처리합니다. 아마도 "비동 사적으로"보내는 것일 수도 있습니다. – selbie

+0

두 개의 서로 다른 스레드가 있으므로 논 블로킹 입출력을 선택하지 않아도됩니다. 각 스레드가 I/O를 차단하도록하십시오. recv에서 시간 초과가 필요하면 [this solution] (http://stackoverflow.com/questions/2876024/linux-is-here-a-read-or-recv-from-socket-with-timeout)을 사용하십시오. – jxh

답변

4

select은 디 멀티플렉싱 메커니즘입니다. 데이터를 단일 소켓이나 타임 아웃에서 언제 준비 할지를 결정하는 동안 실제로 여러 소켓에서 데이터 준비 상태를 반환하도록 설계되었습니다 (따라서 fd_set). 개념적으로 poll, epollkqueue과 동일합니다. 비 차단 I/O와 결합 된이 메커니즘은 응용 프로그램 작성자에게 단일 스레드 동시 서버를 구현하는 도구를 제공합니다.

제 생각에는 응용 프로그램에 그런 종류의 힘이 필요하지 않습니다. 응용 프로그램은 두 개의 연결 만 처리하며 이미 연결 당 하나의 스레드를 사용하고 있습니다. 소켓을 I/O 모드 차단 상태로 두는 것이 더 적절하다고 생각합니다.

비 차단 모드를 고집하는 경우 select 전화를 다른 것으로 바꿔야합니다. select에서 원하는 것은 단일 소켓에 대한 읽기 준비 또는 시간 초과를 나타내는 것이므로 recv이 적절한 매개 변수와 함께 전달되고 소켓에 적절한 시간 초과가 설정된 상태에서 비슷한 효과를 얻을 수 있습니다. man recv에서

tm.tv_sec = time; 
tm.tv_usec = 0; 
setsockopt(connectedSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tm, sizeof(tm)); 
char c; 
swtich (recv(connectedSocket, &c, 1, MSG_PEEK|MSG_WAITALL)) { 
case -1: 
    if (errno == EAGAIN) { 
     // handle timeout ... 
    } else { 
     // handle other error ... 
    } 
    break; 
case 0: // FALLTHROUGH 
default: 
    // handle read ready ... 
    break; 
} 

:

MSG_PEEK -이 플래그는 큐에서 데이터를 제거하지 않고받는 큐의 시작에서 데이터를 반환하는 받기 작동을하도록한다. 따라서 후속 수신 호출은 동일한 데이터를 리턴합니다.

(Linux 2.2부터) -이 플래그는 전체 요청이 충족 될 때까지 연산 블록을 요청합니다. 그러나 신호가 잡히거나 오류 또는 연결 끊김이 발생하거나 수신 할 다음 데이터가 반환 된 데이터와 다른 유형 인 경우 호출은 요청한 것보다 적은 데이터를 반환 할 수 있습니다.

이유에 따라 select이 (가) 관찰하는 방식으로 작동합니다. select 호출은 스레드로부터 안전하지만 재 입력에 대해서는 완벽하게 보호됩니다. 따라서 select에 대한 한 스레드의 호출은 다른 스레드의 호출이 완료된 후에 만 ​​들어옵니다 (select에 대한 호출이 직렬화됩니다). 이는 디멀티플렉서 (demultiplexer)로서의 기능과 인라인입니다. 이것은 연결이 준비되어있는 하나의 중재자 역할을하는 것입니다. 따라서, 그것은 단일 스레드에 의해 제어되기를 원합니다.

+0

recv 함수에서 매개 변수를 설명 할 수 있습니까? –

+0

@Kingfisher : 게시물을 업데이트했습니다. 고마워, 안부. – jxh

+0

@ user315502 'for'루프에서 클라이언트로부터의 'i'' accept' 연결에서'while (true)'루프를 사용했고 클라이언트의 메시지를 수신하기위한 또 다른'for' 루프를 사용했습니다! 그 코드로,'setsockopt'를 넣고'recv'에서 메시지를받는 방식으로'recv'에서 1 문자 만 수신하는 것을 볼 수 있습니다 !! 내가 잘못? –

관련 문제