如何提取消息的长度信息,并从TCP字节流中仅提取那么多的消息? 我试图在C++中通过Socket发送一条消息。我已经阅读了很多关于堆栈溢出的相关问题,但仍然无法理解它是如何工作的。假设我正在向本地主机服务器发送以下字符(M、a、r、t、i、n),人们建议您可以使用4个字节作为长度(即32位,以便它可以处理长度高达4GB的消息)

如何提取消息的长度信息,并从TCP字节流中仅提取那么多的消息? 我试图在C++中通过Socket发送一条消息。我已经阅读了很多关于堆栈溢出的相关问题,但仍然无法理解它是如何工作的。假设我正在向本地主机服务器发送以下字符(M、a、r、t、i、n),人们建议您可以使用4个字节作为长度(即32位,以便它可以处理长度高达4GB的消息),c++,networking,tcp,winsock,C++,Networking,Tcp,Winsock,我在客户端也做了同样的事情,但仍然不知道如何在服务器端解决这个问题,我是只想接收数据的起始3个字节(M,a,r)还是最后3个字节(t,I,n) 我张贴我的代码,请帮助我主要在服务器端,将感谢如果可以写几行相关的代码 Client side code std::vector<char> userbuffer(20); std::cout<<"\nclient:"<<std::endl; char* p = userbuffer.da

我在客户端也做了同样的事情,但仍然不知道如何在服务器端解决这个问题,我是只想接收数据的起始3个字节(M,a,r)还是最后3个字节(t,I,n)

我张贴我的代码,请帮助我主要在服务器端,将感谢如果可以写几行相关的代码

           Client side code
std::vector<char> userbuffer(20);
std::cout<<"\nclient:"<<std::endl;
    char* p = userbuffer.data();
    *p = 'M';
            ++p; *p = 'a';
            ++p; *p = 'r';
            ++p; *p = 't';
            ++p; *p = 'i'; 
            ++p; *p = 'n';
            size_t length = strlen(userbuffer.data());
    uint32_t nlength = htonl(length);
            //line containg message length information
           int header_info = send(socketFD, (char*)&nlength, 4, 0); 
           // Data bytes send to the server
    int bytes_sent = send(socketFD, userbuffer.data(), length, 0);

    if(bytes_sent == SOCKET_ERROR){ //some errror handling}





 Server Side Code
 char receivebuffer[MAX_DATA] = { '\0' };
 int bytesReceivedFromClientMsg = 1;
 int length_bytes = 0;
 uint32_t length, nlength;
 //code to check length if we have received whole data length
 while(length_bytes < 4){
 int read = recv(clientSocket, ((char*)&nlength)+length_bytes, (4-length_bytes), 0);
 if (read == -1) { //error handling}
 length_bytes += read;}
// Most painfull section to understand.
// I implemented this code from some ideas on internet 
//but still cant find how its extracting length and what i am reading :(
       while(bytesReceivedFromClientMsg > 0){
    int msgheader = recv(clientSocket,(char*)&nlength,6, 0);
    length = ntohl(nlength);//leng value here is in severel thousand size
    char *receivebuffer = new char(length+1);
        bytesReceivedFromClientMsg = recv(clientSocket, receivebuffer, msgheader, 0);
    receivebuffer[length] = 0 ;
    std::cout<<"msg header is :"<<msgheader<<std::endl;
    std::cout<<"msg data is :"<<bytesReceivedFromClientMsg<<std::endl;

        if(bytesReceivedFromClientMsg == SOCKET_ERROR){//some error handling}
客户端代码
std::向量用户缓冲区(20);

你需要一个网络协议的设计。有一些类似SMTP的协议是类似文本的协议。您必须读取字符,直到在类似文本的协议中找到类似新行的终止字符

使用基于消息的协议,您有更好的机会使用高性能协议。您定义了一个标头(在代码中使用但未定义)。在标题中,您可以输入有关长度的信息,可能还有关于下一条消息类型的信息。然后将标题发送到消息正文的前面。在您的示例中,主体是“Martin”

接收器有一个状态“header received”。当未收到完整的标头(或根本没有收到任何内容)时,它将使用标头的大小作为区块大小。它将chunksize字节接收到header变量中。当接收到完整的报头时,接收器将chunksize设置为报头中设置的大小,并将如此多的字节接收到有效负载缓冲区。完成后,状态“header received”再次为false

int receive(socket sock, char * buffer, int chunk_size)
{
    int offset = 0;

    while (chunk_size > 0)
    {
        // add select() here when you have a non-blocking socket.
        int n = recv(sock, buffer+offset, chunk_size);
        // TODO: error handling
        offset += n;
        chunk_size -= n;
    }

    // return amount of received bytes
    return offset;
}

void do_receive(void)
{
    struct {
        int size;
        // other message information
    } header;

    while (true)
    {
        receive(sock, &header, sizeof(header);
        receive(sock, buffer, header.size);
        process_message(buffer, header.size);
    }
}

上面的代码不会通过任何编译器。但是它显示了这个想法。

您还需要接收发送的消息长度(请注意以网络字节顺序发送值并正确地反序列化!)。请您添加一行代码,参考此代码,理论基础我知道,但代码确实没有给出我所期望的,我对网络编程是新手+1,或者,您尽可能多地读取数据,然后使用状态机处理数据(即,我是否有足够的数据用于标题?如果是,则解析标题并更改状态,如果否,则读取更多数据,等等)这可能会稍微更有效,这取决于您如何处理完整的消息以及读取数据的系统调用有多昂贵。。。(你的方法可能更容易实现)。我知道状态机是完全不同的。在上面的示例中,“状态”是程序计数器。在接收报头的状态下,您处于第一个调用中,依此类推。与可以对多个事件作出反应的真实状态机相比,这种方法的灵活性更低。但我认为代码是安静可读的。分解在这里很有用。可能会有更有效的解决方案,但receive函数会以尽可能快的速度接收。你从哪里开始优化?我挑剔,你展示的设计很好,减少你调用recv的次数(以及一次处理超过一个块大小的数据)可能更好,但你需要分析,这取决于你如何处理消息数据。对于“仅将消息作为完整项处理”的情况,您所拥有的是好的。另一种方法是读取“缓冲区大小”,然后处理它所包含的消息,然后在处理完消息后将剩余的数据memmove()移动到缓冲区的前面,或者在消息传入时将其分块处理。