如何提取消息的长度信息并从TCP字节流中仅提取那么多消息?

时间:2014-02-02 13:03:48

标签: c++ networking tcp winsock

我试图在C ++中通过Socket发送消息。我已经阅读了许多与此相关的堆栈溢出问题,但仍无法弄清楚它是如何工作的。假设我正在向本地主机服务器发送以下字符(M,a,r,t,i,n),人们建议您可以使用4个字节作为长度(即32位,以便它可以处理消息到4GB长度)。

我在我的客户端做了同样的事情,但仍然不知道我怎么能在服务器端找出这个东西我是否想要只接收起始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}

1 个答案:

答案 0 :(得分:3)

您需要针对网络协议进行设计。像SMTP这样的协议是类似文本的协议。你必须阅读字符,直到你找到像文本类协议中的新行一样的终止字符。

使用基于消息的协议,您有更好的机会获得高性能协议。您定义标头(在您的代码中使用但未定义)。在标题中,您可以输入有关长度的信息,也可能是有关下一条消息类型的信息。然后在邮件正文前面发送标题。在你的例子中,身体是“马丁”。

接收器具有“接收到的标头”状态。当未收到标题时(或根本没有),它将使用标题的大小作为块大小。它将chunksize字节接收到头变量中。当接收到报头时,接收器将块大小设置为在报头中设置的大小,并且接收到有效负载缓冲区的这么多字节。完成后,状态“收到的标题”再次为假。

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

上面的代码不会传递任何编译器。但它显示了这个想法......