2010-11-29 48 views
0

我是否應該閱讀每個字符,直到它到達\ n字符,將它們全部結合在一起並返回,還是有更好的方法?我應該使用std :: string還是char?如何從套接字讀取並返回單個行?

我嘗試以下兩個例子,但我需要1讀取它們作爲單獨的行

實施例:

std::string sockread() 
{ 
    std::string s; 
    s.resize(DEFAULT_BUFLEN); 
    int result = recv(m_socket, &s[0], DEFAULT_BUFLEN, 0); 

    if (result > 0) { 
     return s; 
    } else if (result == 0) { 
     connected = false; 
    } else { 
     std::cout << "recv failed with error " << WSAGetLastError() << "\n"; 
    } 
    throw std::runtime_error("Socket connection failed!"); 
} 

實施例2:

char sockread(void) 

    { 
    int result; 
    char buffer[DEFAULT_BUFLEN]; 
     result = recv(m_socket, buffer, DEFAULT_BUFLEN, 0); 

     if (result > 0) { 
      return *buffer; 
       } 
      else if (result == 0) 
       { 
      connected = false; 
       return *buffer; 
       } 
      else { 
     printf("recv failed with error: %d\n", WSAGetLastError()); 
     return *buffer; 
     } 

    } 

回答

0

你有一個幾個選項,取決於你的套接字代碼的其他部分是如何佈局的。

從編碼的角度來看,最簡單的方法是每次只讀取1個字符,直到遇到您正在查找的字符。這是不是從性能的角度來看,最好的辦法,雖然你可以使用本地緩存,以幫助您避免碎裂內存至少,例如:

std::string sockread(void) 
{ 
    char buffer[DEFAULT_BUFLEN]; 
    int buflen = 0; 
    char c; 
    std::string s; 

    do 
    { 
     int result = recv(m_socket, &c, 1, 0); 
     if (result > 0) 
     { 
      if (c == '\n') 
       break; 

      if (buflen == DEFAULT_BUFLEN) 
      { 
       s += std::string(buffer, buflen); 
       buflen = 0; 
      } 

      buffer[buflen] = c; 
      ++buflen; 

      continue; 
     } 

     if (result == SOCKET_ERROR) 
     { 
      if (WSAGetLastError() == WSAEWOULDBLOCK) 
       continue; 

      std::cout << "recv failed with error " << WSAGetLastError() << "\n"; 
     } 
     else 
      connected = false; 

     throw std::runtime_error("Socket connection failed!"); 
    } 
    while (true); 

    if (buflen > 0) 
     s += std::string(buffer, buflen); 

    return s; 
} 

在另一方面,讀取原始套接字數據到一箇中間緩衝區在需要的時候你的閱讀功能的訪問,其餘允許插座的更有效的閱讀,這樣的數據得到了套接字的緩衝區更快(導致對對方少阻塞),例如:

std::vector<unsigned char> buffer; 

std::string sockread(void) 
{ 
    unsigned char buf[DEFAULT_BUFLEN]; 
    int result; 
    std:vector<unsigned char>::iterator it; 

    do 
    { 
     it = std::find(buffer.begin(), buffer.end(), '\n'); 
     if (it != buffer.end()) 
      break; 

     result = recv(m_socket, buf, DEFAULT_BUFLEN, 0); 
     if (result > 0) 
     { 
      std::vector<unsigned char>::size_type pos = buffer.size(); 
      buffer.resize(pos + result); 
      memcpy(&buffer[pos], buf, result); 
      continue; 
     } 

     if (result == SOCKET_ERROR) 
     { 
      if (WSAGetLastError() == WSAEWOULDBLOCK) 
       continue; 

      std::cout << "recv failed with error " << WSAGetLastError() << "\n"; 
     } 
     else 
      connected = false; 

     throw std::runtime_error("Socket connection failed!"); 
    } 
    while (true); 

    std::string s((char*)&buffer[0], std::distance(buffer.begin(), it)); 
    buffer.erase(buffer.begin(), it); 
    return s; 
} 
+0

使用第二種方法,我得到這個錯誤 - 錯誤C2664:'recv':無法將參數2從'unsigned char [512]'轉換爲'char *' 指向的類型是無關的;轉換需要reinterpret_cast,C風格轉換或函數風格轉換 – thorvald 2010-11-29 21:30:38

+0

,如果我將其更改爲buf [DEFAULT_BUFLEN](不確定如果我不好),那麼它可以工作,但只返回第一行,其餘爲空字符串。 – thorvald 2010-11-29 22:09:20

0

使用boost .ASIO - 基於行的操作涵蓋here

許多常用互聯網協議 是基於行的,這意味着它們具有 是 由字符序列 「\ r \ n」個分隔的協議元素。例子包括HTTP,SMTP 和FTP。爲了更容易地允許執行基於行的 協議以及使用分隔符的其他協議 ,Boost.Asio 包括函數read_until() 和async_read_until()。