UDP分包组包类 基于boost.asio库实现

基于boost.asio库实现的类,可以发送,接收消息和文件。

参考文章:https://blog.csdn.net/sanmaoljh/article/details/52183723

1.发送消息时都会用数据包发送

2.数据包会用crc32校验码检验,若有误则置错误码为1

3.收到消息后会发送确认消息给发送端,发送端接收后核对,若错误码被置为1则重发数据包

4.算是UDP可靠传输

struct PackageHead{
    unsigned int index;       //包序号
    unsigned int len;   //数据字节数
    unsigned int crc32val;   //校验码
    int errorFlag;   //错误码
};

struct Package{
    PackageHead head;
    char buff[BUFFERSIZE];
};

class UDP
{
public:
    UDP(socket_ptr s);
    int send(char message[], endpoint ep); //发送消息
    std::string receive();  //接收消息

    long int sendFile(FILE *fp, endpoint ep);  ///发送文件
    void receiveFile(FILE *fp);   //接收文件

private:
    socket_ptr sock;  //套接字
};


UDP::UDP(socket_ptr s)
{
    sock = s;
}

int UDP::send(char message[], endpoint ep)
{
    boost::asio::ip::udp::endpoint sender_ep;

    Package data;
    bzero(&data,sizeof (data));
    PackageHead pack_info;
    bzero(&pack_info,sizeof (pack_info));

    unsigned int send_index = 0;
    unsigned int receive_index = 0;

    int returnlen = 0;

    try {
        int len = sizeof(message);
        if( len > MAXLENGTH)  //长度大于512,分包发送
        {
            int readed = 0;
            int count = sizeof(message) / MAXLENGTH;
            while(len){
                memcpy(data.buff,message + readed,MAXLENGTH);
                readed += MAXLENGTH;
                len -= MAXLENGTH;

                if(send_index == receive_index){
                    ++send_index;
                    data.head.index = send_index;
                    if(count == 0)
                        data.head.len = sizeof (message) - readed;
                    data.head.len = MAXLENGTH;
                    --count;
                    data.head.crc32val = crc32(crc,(unsigned char *)data.buff,sizeof(data));

                    returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),ep);
                    sock->receive_from(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
                    receive_index = pack_info.index;

                    if(pack_info.errorFlag == 1)
                    {
                        pack_info.errorFlag = 0;
                        returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),ep);
                    }
                }
                else {
                    //index不同 重新发送
                    returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),sender_ep);
                    sock->receive_from(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
                    receive_index = pack_info.index;
                }
            }
        }
        else { //只需要一个包
            //            std::cout << "leave" << std::endl;
            memcpy(data.buff,message,sizeof (message));
            if(send_index == receive_index){
                ++send_index;
                data.head.index = send_index;
                data.head.len = sizeof (message);
                data.head.crc32val = crc32(crc,(unsigned char *)data.buff,sizeof(data));

                returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),ep);

                sock->receive_from(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
                std::cout << "leave" << std::endl;
                receive_index = pack_info.index;

                if(pack_info.errorFlag == 1)
                {
                    pack_info.errorFlag = 0;
                    returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),ep);
                }
            }
            else {
                //index不同 重新发送
                returnlen = sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),sender_ep);
                sock->receive_from(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
                receive_index = pack_info.index;
            }
        }

    } catch (boost::system::system_error e) {
        std::cerr << e.what() << std::endl;
    }

    return returnlen;
}

std::string UDP::receive()
{
    Package data;
    bzero(&data,sizeof (data));
    PackageHead pack_info;     //返回给客户端包正确的消息
    bzero(&pack_info,sizeof (pack_info));
    unsigned int crc32value;
    long int id = 1;   //包序列号

    char buffer[512];
    bzero(buffer,sizeof (buffer));   //消息缓存

    boost::asio::ip::udp::endpoint sender_ep;

    //检测数据的完整
    size_t len = sock->receive_from(boost::asio::buffer(reinterpret_cast(&data), sizeof(data)),sender_ep);

    if(len < 0)
        std::cout << "Receive Message From Client failed.\n";
    else {
        crc32value = crc32(crc,(unsigned char *)data.buff,sizeof(data));  //生成校验码
        if(data.head.index == id)
        {
            if(data.head.crc32val == crc32value)
            {
                pack_info.index = data.head.index;
                pack_info.len = len;
                ++id;
                sock->send_to(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
                memcpy(buffer,data.buff,sizeof (data.buff));
            }
            else {
                //错误包,重发
                pack_info.index = data.head.index;
                pack_info.len = len;
                pack_info.errorFlag = 1;
                sock->send_to(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
            }
        }
        else if (data.head.index < 0) {//重发包
            pack_info.index = data.head.index;
            pack_info.len = len;
            pack_info.errorFlag = 0;
            sock->send_to(boost::asio::buffer((char *)&pack_info,sizeof(pack_info)),sender_ep);
        }
        else {
            id = 1;
        }
    }
    return buffer;
}

void UDP::receiveFile(FILE *fp)
{
    std::cout << "=====Receive File Context=====" << std::endl;
    int len = 0;
    boost::asio::ip::udp::endpoint sender_ep;

    unsigned int crc32tmp;
    long int id = 1;
    while(1)
    {
        PackageHead head; //定义确认包变量
        Package data;

        len = sock->receive_from(boost::asio::buffer(reinterpret_cast(&data), sizeof(data)),sender_ep);


        if(len > 0)
        {
            crc32tmp = crc32(crc,(unsigned char *)data.buff,sizeof(data));

            if(data.head.index == id)
            {
                if(data.head.crc32val == crc32tmp)
                {
                    head.index = data.head.index;
                    head.len = len;
                    ++id;

                    sock->send_to(boost::asio::buffer((char *)&head,sizeof(head)),sender_ep);

                    fwrite(data.buff,sizeof (char),data.head.len,fp);
                }
                else {
                    //错误包,重发
                    head.index = data.head.index;
                    head.len = len;
                    head.errorFlag = 1;

                    sock->send_to(boost::asio::buffer((char *)&head,sizeof(head)),sender_ep);
                }
            }
            else if(data.head.index < id){ //重发包
                head.index = data.head.index;
                head.len = len;
                head.errorFlag = 0;

                sock->send_to(boost::asio::buffer((char *)&head,sizeof(head)),sender_ep);
            }
            else {
                break;
            }
        }
        else {
            std::cout << "accept " << std::endl;
            break;
        }
    }
    fclose(fp);
    std::cout << "Transfer successful." << std::endl;
}

long UDP::sendFile(FILE *fp,endpoint ep)
{
    boost::asio::ip::udp::endpoint sender_ep;
    //发送文件内容
    long int send_id = 0;
    long int receive_id = 0;

    int len = 0; //记录数据长度

    Package data;

    long int total_bytes_read = 0;

    while(true)
    {
        PackageHead head;
        Package data;

        bzero((char *)&data,sizeof(data));

        if(receive_id == send_id)
        {
            ++send_id;

            len = fread(data.buff,sizeof(char),BUFFERSIZE,fp);
            total_bytes_read += len;
            if(len > 0)
            {
                data.head.index = send_id;
                data.head.len = len;
                data.head.crc32val = crc32(crc,(unsigned char *)data.buff,sizeof(data));

                //                std::cout<< "len " << len << std::endl;
                //                std::cout << "crc32: " << data.head.crc32val << std::endl;

                sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),ep);

                sock->receive_from(boost::asio::buffer((char *)&head,sizeof(head)),sender_ep);
                receive_id = head.index;

                //                std::cout << "receive: " << head.index << std::endl;

                if(head.errorFlag == 1)
                {
                    head.errorFlag = 0;
                    sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),sender_ep);
                }
            }
            else {
                break;
            }
        }
        else{
            //index不同 重新发送
            sock->send_to(boost::asio::buffer((char *)&data,sizeof(data)),sender_ep);
            sock->receive_from(boost::asio::buffer((char *)&head,sizeof(head)),sender_ep);
            receive_id = head.index;
        }
    }
    bzero((char *)&data,sizeof(data));
    sock->send_to(boost::asio::buffer((char *)&data,0),sender_ep);
    return total_bytes_read;
}

 

你可能感兴趣的:(C++,网络编程)