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;
}
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;
}
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 _DEBUGchar 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;}
4)User_Enet_DisConnect断开连接函数
int User_Enet_DisConnect(ENetHost *host, ENetPeer *peer)
{int ret;#ifdef _DEBUGchar 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);#endifENetEvent 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;}
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);}
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;}
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;}
使用举例
客户端:
User_Enet_Connect->User_Enet_SendMsg或User_Enet_Send->User_Enet_WaitAck
服务端:
User_Enet_Listen->User_Enet_Accept->User_Enet_Recv或是User_Enet_RecvMsg