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

发布于 2024-10-04 14:59:09 字数 1117 浏览 0 评论 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;
        }

   }

Am I supposed to read each character until it reaches the \n character, join them all together and return or is there a better way? Should I use std::string or char for this?

I tried the following two examples but I need to read them as separate lines

Example 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!");
}

Example 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;
        }

   }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

善良天后 2024-10-11 14:59:09

您有几个选择,具体取决于套接字代码的其余部分的布局方式。

从编码的角度来看,最简单的方法是一次只读取 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;
}

You have a few options, depending on how the rest of your socket code is laid out.

The simpliest approach, from a coding perspective, is to just read 1 char at a time until you encounter the char you are looking for. This is not the best approach from a performance perspective, though you can use a local buffer to help you avoid fragmenting memory at least, eg:

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;
}

On the other hand, reading the raw socket data into an intermediate buffer that the rest of your reading functions access when needed allows for more efficient reading of the socket so the data is gotten out of the socket's buffers quicker (causing less blocking on the other side), eg:

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;
}
梦萦几度 2024-10-11 14:59:09

使用Boost.ASIO - 基于行的操作这里

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

Use Boost.ASIO - line-based operations covered here.

Many commonly-used internet protocols
are line-based, which means that they
have protocol elements that are
delimited by the character sequence
"\r\n". Examples include HTTP, SMTP
and FTP. To more easily permit the
implementation of line-based
protocols, as well as other protocols
that use delimiters, Boost.Asio
includes the functions read_until()
and async_read_until().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文