Как читать из сокета и возвращать отдельные строки? - PullRequest
0 голосов
/ 29 ноября 2010

Должен ли я читать каждый символ, пока он не достигнет символа \ 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 голосов
/ 30 ноября 2010

Использовать Boost.ASIO - покрыты строковые операции здесь .

Многие часто используемые интернет-протоколы являются линейными, что означает, что они есть элементы протокола, которые ограничены последовательностью символов "\ Г \ п". Примеры включают HTTP, SMTP и FTP. Чтобы легче было реализация на основе линии протоколы, а также другие протоколы которые используют разделители, Boost.Asio включает в себя функции read_until () и async_read_until ().

0 голосов
/ 29 ноября 2010

У вас есть несколько вариантов, в зависимости от того, как выложен остальной код вашего сокета.

Самый простой подход, с точки зрения кодирования, состоит в том, чтобы просто читать 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;
}
...