用 C++ 实现一个简单的通信协议

在自己开发服务器软件的时候遇到的问题,如果使用纯粹的char或者文本进行数据通信的话,可读性差不说,而且很容易被截取破解,所以萌生了一个开发自己通信协议的想法,本文章的思路借鉴了 Charles0429 在github上的项目的思想。

在本文章里面,我们数据通信统一采用一个结构体来进行数据通信与传输,它包含一个标志头,数据体与校验码,校验码来保证数据传输的正确性。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#define HEAD_SIZE sizeof(package_head_t)
#define PACKAGE_SIZE sizeof(package_t)
#define CS_SIZE (16 * sizeof(uint8_t))

typedef struct package_head
{
    uint8_t type; /*表明数据类型*/
    uint32_t lenght /*表明整个数据的长度*/
}package_head_t;

typedef struct package
{
    package_head_t head;
    char* data;    /*传输的具体数据*/
    uint8_t CS[16];    /*MD5数据校验,可选*/
}package_t;

以上代码需要包含以下头文件:

1
2
3
4
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <stdint.h>

有了基本的结构定义,那么我们就要对这些进行具体操作了,首先来看看我们的第一个函数。

1
package_t *package_read(int socket_fd);

这个函数拥有一个package_t指针,用来指向已经读取完成了的package。他还有一个参数socket_fd,用来确定从哪个套接字描述符来读取package。 下面我们来看看具体的实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package_t *package_read(int socket_fd)
{
    int recv_len;    /*已经接收到的总字节数*/
    int data_len;    /*数据体的长度*/
    int len;         /*recv接收到的字节数*/
    
    package_t *tmp = (package_t*)malloc(PACKAGE_SIZE);
    /*接受头部信息*/
    while(recv_len<HEAD_SIZE)
    {
        len=recv(socket_fd,tmp,HEAD_SIZE-recv_len,0);
        if(len>0)
        {
            recv_len+=len;
        }
    }
    
    recv_len=0;
    data_lenght=get_lenght(tmp);    /*获取数据长度*/
    /*初始化数据体*/
    tmp->data=(char*)malloc(sizeof(char)*data_lenght);
    /*接受数据体*/
    while(recv_len<data_lenght)
    {
        len=recv(socket_fd,tmp,data_lenght-recv_len,0);
        if(len>0)
        {
            recv_len+=len;
        }
    }
    
    recv_len=0;
    while(recv_len<CS_SIZE)
    {
        len=recv(socket_fd,tmp_data,CS_SIZE-recv_len,0);
        if(len>0)
        {
            recv_len+=len;
        }
    }
}

上面用到了一个函数get_lenght(),实际就是取package的数据体长度。

1
2
3
4
uint32_t get_lenght(package_t *pack)
{
    return pack->data_lenght;
}

这个代码思路很简单,依次使用recv读取到数据,每次读取之后的len长度相加,直到读取完成。 下面再写一个发送package_t的函数,用户将我们的数据发送给 服务端/客户端。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void package_write(int socket_fd,void *package)
{
    int send_len;
    int len;
    int data_lenght;

    package_t *tmp = (package_t*)package;
    
    while(send_len<HIDE_SIZE)
    {
        len=send(socket_fd,tmp,HEAD_SIZE-send_len);
        if(len>0)
        {
            send_len+=len;
        }
    }
    send_len=0;
    data_lenght=get_lenght(tmp);
    while(send_len<data_lenght)
    {
        len=send(socket_fd,tmp->data,data_lenght-send_len);
        if(len>0)
        {
            send+=len;
        }
    }
    send_len=0;
    while(send_len<CS_SIZE)
    {
        len=send(socket_fd,tmp->CS,CS_SIZE-send_len);
        if(len>0)
        {
            send_len+=len;
        }
    }
}
Built with Hugo
主题 StackJimmy 设计