c++ - 在 C/C++ 中从 TCP 套接字读取的正确方法是什么?

这是我的代码:

// Not all headers are relevant to the code snippet.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <cstdlib>
#include <cstring>
#include <unistd.h>

char *buffer;
stringstream readStream;
bool readData = true;

while (readData)
{
    cout << "Receiving chunk... ";

    // Read a bit at a time, eventually "end" string will be received.
    bzero(buffer, BUFFER_SIZE);
    int readResult = read(socketFileDescriptor, buffer, BUFFER_SIZE);
    if (readResult < 0)
    {
        THROW_VIMRID_EX("Could not read from socket.");
    }

    // Concatenate the received data to the existing data.
    readStream << buffer;

    // Continue reading while end is not found.
    readData = readStream.str().find("end;") == string::npos;

    cout << "Done (length: " << readStream.str().length() << ")" << endl;
}

如您所知,它有点像 C 和 C++。 BUFFER_SIZE 是 256 - 我应该增加大小吗?如果是这样,该怎么办?有关系吗?

我知道如果出于某种原因没有收到“end”,这将是一个无限循环,这很糟糕 - 所以如果你能提出更好的方法,也请这样做。

最佳答案

在不了解您的完整应用程序的情况下,很难说解决问题的最佳方法是什么,但一种常见的技术是使用以固定长度字段开头的 header ,该字段表示消息其余部分的长度.

假设您的 header 仅包含一个 4 字节整数,表示您的消息其余部分的长度。然后只需执行以下操作。

// This assumes buffer is at least x bytes long,
// and that the socket is blocking.
void ReadXBytes(int socket, unsigned int x, void* buffer)
{
    int bytesRead = 0;
    int result;
    while (bytesRead < x)
    {
        result = read(socket, buffer + bytesRead, x - bytesRead);
        if (result < 1 )
        {
            // Throw your error.
        }

        bytesRead += result;
    }
}

然后在后面的代码中

unsigned int length = 0;
char* buffer = 0;
// we assume that sizeof(length) will return 4 here.
ReadXBytes(socketFileDescriptor, sizeof(length), (void*)(&length));
buffer = new char[length];
ReadXBytes(socketFileDescriptor, length, (void*)buffer);

// Then process the data as needed.

delete [] buffer;

这做了一些假设:

  • 发送方和接收方的整数大小相同。
  • 发送方和接收方的字节序相同。
  • 您可以控制双方的协议(protocol)
  • 发送消息时,您可以预先计算长度。

由于通常希望明确知道您通过网络发送的整数的大小,因此在头文件中定义它们并明确使用它们,例如:

// These typedefs will vary across different platforms
// such as linux, win32, OS/X etc, but the idea
// is that a Int8 is always 8 bits, and a UInt32 is always
// 32 bits regardless of the platform you are on.
// These vary from compiler to compiler, so you have to 
// look them up in the compiler documentation.
typedef char Int8;
typedef short int Int16;
typedef int Int32;

typedef unsigned char UInt8;
typedef unsigned short int UInt16;
typedef unsigned int UInt32;

这会将上面的内容更改为:

UInt32 length = 0;
char* buffer = 0;

ReadXBytes(socketFileDescriptor, sizeof(length), (void*)(&length));
buffer = new char[length];
ReadXBytes(socketFileDescriptor, length, (void*)buffer);

// process

delete [] buffer;

我希望这会有所帮助。

https://stackoverflow.com/questions/666601/

相关文章:

c++ - OpenCV:获取 3 channel RGB 图像,拆分 channel 并仅使用 R

c++ - 在 C++ 中,是否可以获取函数的返回类型以便在不调用该函数的情况下声明一个变量?

c++ - 如何获得 high_resolution_clock 的精度?

c++ - 对两个对应的数组进行排序

c++ - 为什么 std::get() 不能用于获取 vector 的成员?

c++ - 不能在数组上使用 .begin() 或 .end()

c++ - 为什么 PRIu64 在此代码中不起作用?

c++ - 如何检查 STL 迭代器是否指向任何东西?

c++ - 使用 boost::graph 获取特定边缘

c++ - 了解 double 到 int64_t 的转换