2010-11-29 20 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()。