如何从套接字读取并返回单独的行?

时间:2010-11-29 18:36:26

标签: visual-studio-2010 visual-c++ visual-c++-2010 winsock2

我是否应该阅读每个角色,直到它到达\ 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;
        }

   }

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:0)

使用Boost.ASIO - 基于行的操作涵盖here

  

许多常用的互联网协议   是基于行的,这意味着它们   有协议元素   由字符序列分隔   “\ r \ n”。示例包括HTTP,SMTP   和FTP。更容易许可   实现基于行的   协议,以及其他协议   使用分隔符,Boost.Asio   包括函数read_until()   和async_read_until()。