P2P穿透(ENet丢包重传)
资源链接: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个channel0, 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个Channelpeer = 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丢包重传)相关推荐
- Android IOS WebRTC 音视频开发总结(八十七)-- WebRTC中丢包重传NACK实现分析
Android IOS WebRTC 音视频开发总结(八十七)-- WebRTC中丢包重传NACK实现分析 本文主要介绍WebRTC中丢包重传NACK的实现,作者:weizhenwei ,文章最早发表 ...
- android蓝牙丢包重传,华为TE Desktop Mobile软终端引领市场
[IT168厂商动态] 华为自从2013年推出TE30以后,随着视讯行业的迅猛发展与客户对视讯要求的不断提高,华为继续推出了TE40.TE50.TE60三款全新的高清视频会议终端,能全方位覆盖从中小型 ...
- TCPIP协议栈的心跳、丢包重传、连接超时机制实例详解
目录 1.问题概述 2.TCPIP协议栈的心跳机制 2.1.TCP中的ACK机制 2.2.TCPIP协议栈的心跳机制说明 2.3.修改TCPIP协议栈的默认心跳参数 3.libwebsockets开源 ...
- Wireshark tcptrace图关于丢包重传细节图解
上周六写了< 在Wireshark的tcptrace图中看清TCP拥塞控制算法的细节(CUBIC/BBR算法为例)>,收到一封邮件,说我文中的图示画错了. 确实,关于CUB ...
- UDP 分片 与 丢包,UDP 真的比 TCP 高效吗?
关注.星标公众号,直达精彩内容 素材来源:https://blog.csdn.net/LearnLHC/article/details/115268028 整理:技术让梦想更伟大 | 李肖遥 一.UD ...
- UDP 分片 与 丢包,UDP 真的比 TCP 高效吗?UDP 的应用场景
目录 一.UDP 报文格式 二.UDP 分片 1.UDP 有发送缓存区吗? 1>.先说结论: 2>.逐步分析: 2.UDP 分片 1>.UDP 包最佳传输大小 2>.分片问题 ...
- 网络编程之网络丢包故障如何定位?如何解决?
引言 本期分享一个比较常见的网络问题--丢包.例如我们去ping一个网站,如果能ping通,且网站返回信息全面,则说明与网站服务器的通信是畅通的,如果ping不通,或者网站返回的信息不全等,则很可能是 ...
- 云网络丢包故障定位全景指南
作者简介:冯荣,腾讯云网络高级工程师,腾讯云网络核心开发人员. 万字长文 建议收藏 引言 本期分享一个比较常见的⽹络问题--丢包.例如我们去ping⼀个⽹站,如果能ping通,且⽹站返回信息全⾯,则 ...
- linux 丢包排查思路简述(tcp+rdma)
linux 丢包排查思路简述 概述 网络包接收流程 网络包发送流程 丢包排查的思路 tcp排查方法 rdma排查方法 网络工具汇总 参考链接 概述 我们首先以tcp网络为例,谈谈linux系统如何收发 ...
最新文章
- 探React Hooks
- Android init.rc文件格式解析
- Weblogic Admin Console
- 智能机器人服务广州春运
- 文件包含和文件上传结合
- StringBuilder字符串缓冲区
- imagettftext php7,mac php7 imagettftext
- pat 乙级 1016 部分A+B(C++)
- Opencv——写入或读取数据到XML或YAML文件
- 爬虫案列:京东商城长裤信息获取
- 如何尽量规避XSS(跨站点脚本)攻击
- 蓝桥杯 ALGO-110 算法训练 字符串的展开
- eNSP进行配置网络模拟网络联通
- matlab批量裁剪图像并保存,matlab批量裁剪tif图片
- windows下如何使用配置七牛qshell命令工具
- 学习光线追踪(16)---折射计算[1]
- Rest Stops 题解
- 《Wasserstein GAN》继续 GAN
- uni-app App端优化
- MFC开发——卡拉OK字幕制作
热门文章
- JavaEE入门级别最全教程2--初学者必看
- Content-Type为“multipart/form-data“是什么意思?
- qt 菜单/右键快捷菜单 选项不可操作/背景/分隔线颜色样式表
- matlab randperm函数
- 写2300字关于灌注桩施工质量管控的文章
- 前端页面的序号顺序排列index
- 游戏中的AI玩伴,会是“神队友”吗?
- C语言实现链表的逆序的几种方式
- 推荐一款好用的在线笔记工具evernote
- C. Yet Another Tournament