• C++ Enet通信封装


    C++ Enet通信封装


    Enet底层封装的是UDP通信,本文介绍了enet如何实现可靠udp传输的代码封装

    接口封装

    1)User_Enet_Listen监听端口函数

    int User_Enet_Listen(const char *ip, int port, ENetHost **host)
    {    
    	ENetAddress address;  
        if(!strcmp(ip, "*"))
    		ip = "0.0.0.0";
    	if(enet_address_set_host_ip(&address, ip)){
    		fprintf(stderr, "enet_address_set_host_ip %s fail", ip);
    		return -1;
    	}
        address.port = port;
        assert(host);
        *host = enet_host_create(&address, 1, 1, 0, 0);
        if(NULL==*host){
        	fprintf(stderr, "enet_host_create %s:%d fail", address.host, address.port);
        	return -1;
        }
    	int size = 1024*1024*1024;
       	if(enet_socket_set_option((*host)->socket, ENET_SOCKOPT_RCVBUF, size)){
        	fprintf(stderr, "enet set server socket rcvbuf %d bytes fail", size);
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2)User_Enet_Accept接受链接函数

    int User_Enet_Accept(ENetHost *host, unsigned int timeout, ENetPeer **peer)
    {
    	int ret;
    	ENetEvent event;
        ret = enet_host_service(host, &event, timeout);
    	if(ret > 0){        
    		if(event.type != ENET_EVENT_TYPE_CONNECT){
    			if(event.type == ENET_EVENT_TYPE_RECEIVE)
                     enet_packet_destroy(event.packet);
    			fprintf(stderr, "enet_host_service event type %d is not connect", event.type);
    			return -1;
             }         
             assert(peer);
             *peer = event.peer;         
         }else if(0==ret){
             fprintf(stderr, "enet_host_service timeout %d", timeout);
             return -1;         
         }else{
             fprintf(stderr, "enet_host_service fail");
             return -1;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3)User_Enet_Connect建立连接函数

    int User_Enet_Connect(const char *srv_ip, int srv_port, unsigned int conn_timeout, unsigned int rw_timeout, ENetHost **host, ENetPeer **peer)
    {    
          assert(host);
         *host = enet_host_create(NULL, 1, 1, 0, 0);
         if(NULL==*host){
             fprintf(stderr, "enet_host_create fail");
             goto fail;
         }
         if(enet_socket_set_option((*host)->socket, ENET_SOCKOPT_RCVBUF, 1024*1024*1024)){
                fprintf(stderr, "enet set server socket rcvbuf 1M bytes fail");
         }
         
         ENetAddress srv_addr;
         if(enet_address_set_host_ip(&srv_addr, srv_ip)){
             fprintf(stderr, "enet_address_set_host_ip %s fail", srv_ip);
             goto fail;
         }
         srv_addr.port = srv_port;
         
         assert(peer);
         *peer = enet_host_connect(*host, &srv_addr, 1, 0); 
         if(*peer==NULL){
                 fprintf(stderr, "enet_host_connect %s:%d fail", srv_ip, srv_port);
             goto fail;
         }
     
         enet_peer_timeout(*peer, 0, rw_timeout, rw_timeout);
         
         int cnt = 0;
         ENetEvent event;
     
         while(1){
             ret = enet_host_service(*host, &event, 1);
             if(ret == 0){    
                 if(++cnt >= conn_timeout){ 
                        fprintf(stderr, "enet_host_service timeout %d", conn_timeout);
                     goto fail;
                 }
             
             }else if(ret > 0){
                 if(event.type != ENET_EVENT_TYPE_CONNECT){     
                         fprintf(stderr, "enet_host_service event type %d is not connect", event.type);
                         goto fail;
                 }
                 break; //connect successfully
     
             }else{
                     fprintf(stderr, "enet_host_service fail");        
                 goto fail;
             }
         }
     
     #ifdef _DEBUG
         char local_ip[16], foreign_ip[16];
         ENetAddress local_addr;
     
         enet_socket_get_address((*host)->socket, &local_addr);
         enet_address_get_host_ip(&local_addr, local_ip, sizeof(local_ip));
         enet_address_get_host_ip(&(*peer)->address, foreign_ip, sizeof(foreign_ip));
         
         printf("%s:%d connected to %s:%d", local_ip, loca_addr.port, foreign_ip, (*peer)->address.port);
     #endif 
         return 0;     
     fail:
         if(*host) enet_host_destroy(*host); 
         return -1;
     }
    
    • 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
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    4)User_Enet_DisConnect断开连接函数

     int User_Enet_DisConnect(ENetHost *host, ENetPeer *peer)
    {
         int ret;
      
      #ifdef _DEBUG
         char local_ip[16], foreign_ip[16];
         ENetAddress local_addr;
      
         enet_socket_get_address(host->socket, &local_addr);
         enet_address_get_host_ip(&local_addr, local_ip, sizeof(local_ip));
         enet_address_get_host_ip(&peer->address, foreign_ip, sizeof(foreign_ip));
         
         printf("%s:%d is disconnected from %s:%d", local_ip, local_addr.port, foreign_ip, peer->address.port);
     #endif
     
         ENetEvent event;
         enet_peer_disconnect(peer, 0);
             
         while((ret = enet_host_service(host, &event, peer->roundTripTime)) > 0){
             switch (event.type){
             case ENET_EVENT_TYPE_RECEIVE:
                 enet_packet_destroy (event.packet);
                 break;
         
             case ENET_EVENT_TYPE_DISCONNECT:
                 ret = 0;
                 goto disconn_ok;
             }
         }
         ret = 0==ret ? 1 : -1;
     
         fprintf(stderr, "enet_host_service with timeout %d %s", peer->roundTripTime, 1==ret?"timeout":"failure");
         
         enet_peer_reset(conn->peer);
     
     disconn_ok:    
         enet_host_destroy(host);
         return ret;
     }
    
    • 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

    5)User_Enet_SendMsg发送数据函数

    int User_Enet_SendMsg(ENetHost *host, ENetPeer *peer, ENetPacket *packet)
      {
          int ret;
          
          if(enet_peer_send(peer, 0, packet)){
              fprintf(stderr, "enet send packet %lu bytes to peer fail", packet->dataLength);
              return -1;
          }
      
         ret = enet_host_service(host, NULL, peer->roundTripTime);
         if(ret >= 0){
             if(peer->state == ENET_PEER_STATE_ZOMBIE){
                 fprintf(stderr, "enet peer state is zombie");
                 return -1;
             }
             return packet->dataLength;
             
         }else{
             fprintf(stderr, "enet host service %u millsecond failure", peer->roundTripTime);
             return -1;
         }
     }
     
     int User_Enet_Send(ENetHost *host, ENetPeer *peer, const void *buf, size_t len)
     {
         int ret;
     
         ENetPacket *packet = enet_packet_create(buf, len, ENET_PACKET_FLAG_RELIABLE);
         if(NULL==packet){        
             fprintf(stderr, "enet create packet %lu bytes fail", sizeof(int)+len);
             return -1;
         }
     
         return User_Enet_SendMsg(host, peer, packet);
     }
    
    • 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

    6)User_Enet_RecvMsg接收数据函数

    int User_Enet_RecvMsg(ENetHost *host, ENetPeer *peer, ENetPacket **packet, unsigned int timeout)
      {
          int ret;
          ENetEvent event;
      
          ret = enet_host_service(host, &event, timeout);
          if(ret > 0){
              if(event.peer != peer){
                  fprintf(stderr, "enet receive peer is not matched");
                 goto fail;
             }
             if(event.type != ENET_EVENT_TYPE_RECEIVE){
                 fprintf(stderr, "enet receive event type %d is not ENET_EVENT_TYPE_RECEIVE", event.type);
                 goto fail;
             }
             
             *packet = event.packet;
             return*packet)->dataLength;
            
     fail:
             enet_packet_destroy(event.packet);
             return -1;
             
         }else {
             fprintf(stderr, "enet receive %u millsecond %s", timeout, ret?"failure":"timeout");
             return -1;        
         }
     }
     
     int User_Enet_Recv(ENetHost *host, ENetPeer *peer, void *buf, size_t maxlen, unsigned int timeout) 
     {
         ENetPacket *packet;
     
         if(-1==User_Enet_RecvMsg(host, peer, &packet, timeout))
             return -1;
     
         if(packet->dataLength > maxlen) {
             fprintf(stderr, "enet packet data length %d is greater than maxlen %lu", packet->dataLength, maxlen);
             return -1;
         }
     
         memcpy(buf, packet->data, packet->dataLength);
         enet_packet_destroy(packet);
         
         return packet->dataLength;
     }
    
    • 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
    • 42
    • 43
    • 44
    • 45
    • 46

    7)User_Enet__WaitAck 等待所有确认函数
    发送数据的确认,需根据对端状态判断是否断线

     int User_Enet__WaitAck (ENetHost *host, ENetPeer *peer, unsigned int timeout)
      {
          int ret, cnt = 0;
          
          while((ret = enet_host_service(host, NULL, 1)) >= 0){        
              if(enet_peer_is_empty_sent_reliable_commands(peer, 0, 
                  ENET_PROTOCOL_COMMAND_SEND_RELIABLE|ENET_PROTOCOL_COMMAND_SEND_FRAGMENT))
                  return 0;
     
             if(peer->state == ENET_PEER_STATE_ZOMBIE){
                 fprintf(stderr, "enet peer state is zombie");
                 return -1;
             }
         
             if(0==ret && ++cnt>=timeout){
                 return 1;
             }
         }
         
         fprintf(stderr, "enet host service fail");
         return -1;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    使用举例

    客户端:
    User_Enet_Connect->User_Enet_SendMsg或User_Enet_Send->User_Enet_WaitAck
    服务端:
    User_Enet_Listen->User_Enet_Accept->User_Enet_Recv或是User_Enet_RecvMsg

  • 相关阅读:
    图像增强之灰度变换
    Object.assign和&&
    机器学习性能评估指标
    leetcode-链表类题目
    通过free命令了解Linux系统内存状态
    MySQL的级联操作
    详解初阶数据结构之顺序表(SeqList)——单文件实现SeqList的增删查改
    《第一堂棒球课》:王牌捕手·棒球2号位
    C程序是如何跑起来的01 —— 普通可执行文件的构成
    算法设计与分析 | 页码统计
  • 原文地址:https://blog.csdn.net/techenliu/article/details/132744386