P2P穿透(ENet丢包重传)
来源:互联网 发布:mac优酷弹幕怎么设置 编辑:程序博客网 时间:2024/06/06 07:23
资源链接:http://download.csdn.net/download/yuanchunsi/10159049
P2P穿透成功后,获得对端IP和端口通过ENet进行连接传输数据,解决了UDP丢包视频卡顿的问题!
服务端:
/* * =========================================================================== * * Filename: enetc.c * Description: * Version: 1.0 * Created: 2017年12月11日 14时10分03秒 * Revision: none * Compiler: gcc * Author: (ycs), * Company: * * =========================================================================== */#include<string.h>#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include"enet/enet.h"//全局变量pthread_t pthread_S;pthread_t pthread_R;ENetPeer *peer = NULL;ENetHost *host = NULL;ENetEvent event; //模拟媒体数据结构typedef struct code_{ char data[128]; int size ;}tmp_t;//发送数据线程,模拟项目框架void *run_s(void*data){ pthread_detach(pthread_self()); static int count = 0; while(1) { sleep(1); if(NULL != peer) { ENetPacket *packet = enet_packet_create(NULL,78,ENET_PACKET_FLAG_RELIABLE);//ENET_PACKET_FLAG_RELIABLE:这个flag表示支持丢包重发 char tmp[78]; snprintf(tmp,78,"%s count: %d","I am server",count++);//发送带有seq的数据模拟RTP的序列号,确保ENet发送无异常 //strcpy((char*)packet->data,tmp);memcpy((char*)packet->data,tmp,78);//此处很重要,媒体数据不能用strcpy!!! enet_peer_send(peer,2,packet); enet_host_flush(host); } }}//接收数据线程,模拟项目框架void *run_R(void*data){ pthread_detach(pthread_self()); static int count = 0; while (enet_host_service (host, &event, 5000)>=0) { printf("event type == %d\n",event.type); if(event.type == ENET_EVENT_TYPE_CONNECT){ peer = event.peer; char ip[256]; ENetAddress remote = event.peer->address; enet_address_get_host_ip(&remote,ip,256); printf("ip %s port %d\n",ip,remote.port); } else if(event.type == ENET_EVENT_TYPE_RECEIVE){ printf("datalenth %d %s channel %d\n",event.packet->dataLength,event.packet->data,event.channelID); //接收媒体数据 tmp_t tmp; tmp.size = event.packet->dataLength; memcpy(tmp.data,event.packet->data,tmp.size); printf("data: %s size: %d\n",tmp.data,tmp.size); enet_packet_destroy(event.packet); } else if(event.type == ENET_EVENT_TYPE_DISCONNECT){ printf("peer is disconnect \n"); } } }int main(){ int ret = -1; if(enet_initialize()) { printf("init failed\n"); return -1; } ENetAddress haddr; haddr.host = ENET_HOST_ANY; haddr.port=1234; //创建本地Host,绑定地址和端口 host = enet_host_create(&haddr, 15, //允许15个客户端连接 3, //有3个channel 0, 0); if(host == NULL) { printf("create failed\n"); return -1; } //模拟项目框架,发送和接收为两个线程 ret = pthread_create(&pthread_S,NULL,run_s,NULL); ret = pthread_create(&pthread_R,NULL,run_R,NULL); getchar(); enet_deinitialize(); return 0;}
客户端:
/* * =========================================================================== * * Filename: enetc.c * Description: * Version: 1.0 * Created: 2017年12月11日 14时10分03秒 * Revision: none * Compiler: gcc * Author: (ycs), * Company: * * =========================================================================== */#include<string.h>#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include"enet/enet.h"//全局变量pthread_t pthread_S;pthread_t pthread_R;ENetPeer *peer = NULL;ENetHost *host = NULL;ENetEvent event; //发送数据线程,模拟项目框架void *run_s(void*data){ pthread_detach(pthread_self()); static int count = 0; while(1) { sleep(1); if(NULL != peer) { ENetPacket *packet = enet_packet_create(NULL,78,ENET_PACKET_FLAG_RELIABLE);//ENET_PACKET_FLAG_RELIABLE:这个flag表示支持丢包重发 char tmp[78]; snprintf(tmp,78,"%s count: %d","I am client",count++);//发送带有seq的数据模拟RTP的序列号,确保ENet发送无异常 //strcpy((char*)packet->data,tmp);memcpy((char*)packet->data,tmp,78);//此处很重要,媒体数据不能用strcpy!!! enet_peer_send(peer,2,packet); enet_host_flush(host); } }}//接收数据线程,模拟项目框架void *run_R(void*data){ pthread_detach(pthread_self()); static int count = 0; while (enet_host_service (host, &event, 5000)>=0) { printf("event type == %d\n",event.type); if(event.type == ENET_EVENT_TYPE_CONNECT){ peer = event.peer; char ip[256]; ENetAddress remote = event.peer->address; enet_address_get_host_ip(&remote,ip,256); printf("ip %s port %d\n",ip,remote.port); } else if(event.type == ENET_EVENT_TYPE_RECEIVE){ printf("datalenth %d %s channel %d\n",event.packet->dataLength,event.packet->data,event.channelID); enet_packet_destroy(event.packet); } else if(event.type == ENET_EVENT_TYPE_DISCONNECT){ printf("peer is disconnect \n"); } } }int main(){ int ret = 0; //初始化 if(enet_initialize()) { printf("init failed\n"); return -1; } //创建本地HOST对象,客户端不需要绑定地址 host = enet_host_create(NULL, 1, //只允许连接一个服务器 0, 0, 0); if(host == NULL) { printf("create failed\n"); return -1; } ENetAddress paddr; enet_address_set_host(&paddr,"192.168.0.110");//设备端IP地址,此地址为StunServer提供(P2P穿透成功) paddr.port=1234;//设备端ENet端口,测试端口 //连接设备端ENet,3为设备端3个Channel peer = enet_host_connect(host,&paddr,3,0); if(peer == NULL) { printf("peer connect failed\n"); return -1; } //模拟项目框架,发送和接收为两个线程 ret = pthread_create(&pthread_S,NULL,run_s,NULL); ret = pthread_create(&pthread_R,NULL,run_R,NULL); getchar(); enet_deinitialize(); return 0;}
总结:
1、enet_peer_send():实质把发送数据insert_list。由enet_host_service接口内部实现send操作
2、ENetPacket *packet=enet_packet_create(NULL,ret,ENET_PACKET_FLAG_RELIABLE);
选择合适的FLAGS创建packet
- ENET_PACKET_FLAG_RELIABLE packet must be received by the target peer and resend attempts should be made until the packet is delivered
- ENET_PACKET_FLAG_UNSEQUENCED packet will not be sequenced with other packets not supported for reliable packets
- ENET_PACKET_FLAG_NO_ALLOCATE packet will not allocate data, and user must supply it instead
- ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT packet will be fragmented using unreliable (instead of reliable) sends if it exceeds the MTU
- ENET_PACKET_FLAG_SENT whether the packet has been sent from all queues it has been entered into
3、enet_host_service():很重要,实质接收发送数据都在这个函数做的;包括event事件、获取list,ACK重发。
enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event);//list
enet_protocol_receive_incoming_commands(host, event));//接收
enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int checkForTimeouts);//发送及丢包统计
enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer);这个是判断发送ack,如果ack不正确,会将continueSending置为1,从而让这个while一直循环发送该包。
- P2P穿透(ENet丢包重传)
- P2P之UDP穿透
- p2p tcp 穿透
- P2P穿透NAT原理
- 如何实现P2P穿透
- p2p如何穿透nat
- P2P之UDP穿透
- P2P nat 穿透
- 怎样实现P2P穿透
- p2p nat穿透详解
- P2P穿透&StunServer
- 【智能路由器】openwrt实现内网穿透(p2p、n2n)
- Enet入门(译)
- Enet学习(一)
- ENET(四)enet_protocol_send_acknowledgements
- P2P:UDP穿透NAT防火墙
- P2P UDP NAT 原理 穿透
- P2P:UDP穿透NAT防火墙
- 8、Tensorflow:变量常量类型
- 'node'不是内部或者外部命令,也不是可运行的程序或批处理文件
- 2017/12/14
- 搭建高可用mongodb集群(一)——配置mongodb
- 梯度算法之批量梯度下降,随机梯度下降和小批量梯度下降
- P2P穿透(ENet丢包重传)
- 蓝桥杯 ADV-171 算法提高 身份证号码升级 (java)
- React native应用程序注册表appRegistry
- 免费UNITY资源的超级列表
- wiki confluence 安装
- 第8周 【项目3-顺序串算法】
- 跨平台交叉编译FFmpeg库(Android、IOS、S2L)
- Spring IOC <context:annotation-config>与<context:component-scan/>
- count(*),count(1),count(id),count(rowid)的效率