使用UDP完成网络通信

时间:2021-07-02 06:14:46

语言聊天有可以接受丢包但是不能接受乱序的特性,所以可以采用UDP来

传输数据提高效率。

因为UDP本身不可靠传输的特性,为了保证玩家可靠的接入服务器和一些

操作的正确执行,还是需要一些额外的代码保证UDP的可靠性传输。

一个简单的方案是在发送端发送一个包之后,等待接收端发送的recvack,

如果没有接收到recvack则重复发送直到超时。发送端接到recvack则发送

confrimack。接收端若没有收到confrimack重复发送知道超时。

为了区分可靠和非可靠性传输,为以枚举的形式封包提供了不同的包类型

需要提供不同的:

enum sendtype{

    safe_send,

    unsafe_send,

并且提供不同的发送接口:

void unsafe_send(char* buf,int len,const sockaddr* addr, int addrlen){

    int datalen += sizeofsenddatahead;

    senddata * data = (senddata*)malloc(datalen);

    data->type = unsafe_send;

    data->len = len;

    memcpy(data->data, buf, len);

    sendto(fd, data, datalan, 0, addr, addrlen);

}

void safe_send(char* buf,int len,const sockaddr* addr,int addrlen){

    int datalen += sizeofsenddatahead;

    senddata * data = (senddata*)malloc(datalen);

    data->type = safe_send;

接收端在接收到数据后,如果是safe_send,则发送recvack:

void sendrecvack(sockaddr_in & addr, int addrlen){
  recvack cmd;
  cmd.isrecv = cmdrecvack;
  safe_send(&cmd, sizeofconfrimack, (sockaddr*)&addr, addrlen);

发送端在接收到recvack后,发送confrimack:

void sendconfrimack(sockaddr_in & addr, int addrlen){

    confrimack cmd;

    cmd.isrecv = cmdconfrimack;

    unsafe_send(&cmd, sizeofconfrimack, (sockaddr*)&addr, addrlen);

使用心跳控制重发包:

void safesendheadbeat(int time, void * data){

    if (!vsenddata.empty()){

        senddata * data = vsenddata.front();

        sendto(fd, data, data->len, 0, addr, addrlen);

    }

    addtime(25,  safesendheadbeat, data);

使用心跳控制recvack:

void recvackheadbeat(int time, void * data){

    if (recvack != 0){

        sendto(fd, recvack, recvack->len, 0, addr, addrlen);

    }

    addtime(25,  recvackheadbeat, recvack);