2012-07-31 6 views
1

이 질문은 여러 번 질문했지만 많은 해결책이 저에게는 해당되지 않는 것으로 보입니다. 내가 계속하기 전에 내가 당신을 위해 코드를 조금 게시 할 예정입니다 : 내가 프로그래밍의이 종류에 아주 새로운 오전 (및 선호 overflow- 스택지연과 함께 recv() 문제가 발생했습니다.

string data; 
    { 
     stringstream bodyStream; 

     bodyStream 
      << "POST /api/translation/translate HTTP/1.1\n" 
      << "Host: elfdict.com\n" 
      << "Content-Type: application/x-www-form-urlencoded\n" 
      << "Content-Length: " << (5 + m_word.length()) 
      << "\n\nterm=" << m_word; 

     data = bodyStream.str(); 
    } 

    cout << "Sending HTTP request: " << endl << data << endl; 

: 여기

// Await the response and stream it to the buffer, with a physical limit of 1024 ASCII  characters 
    stringstream input; 
    char buffer[4096*2]; 
    while (recv(sock, buffer, sizeof(buffer) - 1, MSG_WAITALL) > 0) 
     input << buffer; 
    input << '\0'; 

    // Close the TCP connection 
    close(sock); 
    freehostent(hostInfo); 

그리고 나의 요청입니다 그것을 슬그머니 내 머리를 벽에 부딪쳐 문제가 해결 될 때까지 여기에서 길을 잃어 버렸습니다!) 정말 오래 걸리는 이유를 알아내는 데 도움이됩니다. 나는 비 블로킹 (non-blocking)이되도록 설정하는 방법을 살펴 보았지만 예상대로 작동하도록하는 데 문제가 있었다. 어쩌면 여기있는 사람들이 올바른 방향으로 나를 가리킬 수도 있지만, 비 보킹 루트가 내가해야 할 길인 경우.

많은 사람들이 라이브러리 사용을 선호하지만이 방법을 배우고 싶습니다.

저는 Mac에서 프로그래밍하고 소켓으로 작업하는 것을 처음 사용합니다. 아마 처음으로 좋은 프로젝트가 아닐지도 모르지만 지금 시작했습니다! 그래서 나는 계속하고 싶다 :) 어떤 도움이 좋을 것이다!

미리 감사드립니다.

+1

버퍼에 읽은 바이트 수를 기록하고 그 수만큼만 입력에 기록해야합니다. 데이터에 널 종결자가 포함되거나 포함되지 않을 것이라는 보장은 없습니다. – sje397

+0

귀하의 요청에 따라 귀하는 웹 서버와 통신하고 있습니다. 여러분의 요청에 문제가있는 것은 개행입니다. HTTP 표준에 따르면' "\ r \ n"'을 개행 문자로 사용해야하며' '\ n' '을 사용하면 안됩니다. –

답변

1

문제가 발생합니다. 지정된 바이트가 모두 수신 될 때까지 recv을 차단 상태로 유지합니다 (상대방이 보낸 메시지가 분명히 작은 반면 sizeof(buffer) - 1). 오류가 발생하고 errno 변수가 적절하게 설정된 경우 -1이 반환됩니다.

다른 쪽 끝의 소켓이 닫힐 때까지 (recv는 0을 반환) 또는 일부 구분 기호가 수신 될 때까지 더 좋은 옵션은 루프에 플래그가없는 recv을 발생시키는 것입니다.

그러나 recv은 각 반복마다 작은 부분의 데이터 (예 : 20 바이트) 만 반환 할 수 있으므로 정확하게이 양의 데이터를 문자열 스트림에 넣어야하므로 input << buffer을 사용해야합니다. 받은 바이트 수는 recv에 의해 반환됩니다.

2

모두 요청한 데이터, 즉 8k 바이트를 수신하거나 연결에 오류가 있거나 닫히기 전까지 시스템에 대기하라는 이유 때문에 수신하는 데 시간이 오래 걸리는 이유가 있습니다. . 이것은 플래그 MSG_WAITALL이하는 것입니다.

하나의 해결책은 소켓을 비 블로킹으로 만들고 오류가 발생하거나 연결이 닫힐 때까지 루프에서 연속 읽기를 수행하는 것입니다. 그런 다음

int flags = fcntl(sock, F_GETFL, 0); 
flags |= O_NONBLOCK; 
fcntl(sock, F_SETFL, flags); 

당신이 읽기 : 소켓이 그것이 fcntl 기능을 수행 Linux 또는 유사한 시스템에서 ioctlsocket 기능을 수행 Windows에서, 플랫폼에 따라 다릅니다 비 - 블로킹 (non-blocking) 만드는 방법

다음과 같은 소켓 :

std::istringstream input; 

for (;;) 
{ 
    char buffer[256]; 
    ssize_t recvsize; 

    recvsize = recv(sock, buffer, sizeof(buffer) - 1, 0); 
    if (recvsize == -1) 
    { 
     if (errno != EAGAIN && errno != EWOULDBLOCK) 
      break; // An error 
     else 
      continue; // No more data at the moment 
    } 
    else if (recvsize == 0) 
     break; // Connection closed 

    // Terminate buffer 
    buffer[recvsize] = '\0'; 

    // Append to input 
    input << buffer; 
} 

위 루프의 문제점은 데이터가 수신되지 않으면 영원히 반복된다는 것입니다.


그러나, 당신은 당신의 코드에서 훨씬 더 심각한 문제가있다 : 당신은 버퍼에 수신 한 다음이 stringstream에 추가,하지만 당신은 버퍼를 종료하지 않습니다. 스트림에서 문자열을 종료 할 필요는 없으며 자동으로 수행되지만, 을 수행하면에서 버퍼를 종료해야합니다.

는 다음과 같이 해결할 수 있습니다 : 당신이 MSG_WAITALL 플래그를 지정하고 있기 때문에 여기

int rc; 
while ((rc = recv(sock, buffer, sizeof(buffer) - 1, MSG_WAITALL)) > 0) 
{ 
    buffer[rc] = '\0'; 
    input << buffer; 
} 
관련 문제