Reliable Multicast Programming (PGM)实际通用可靠多播协议,在某种程度上保证多播的可靠性。是IP上层协议,和TCP还有UDP同级,工作在传输层。

在组播传输视频项目中,发现在网络较差的时候,组播传输视频性能下降迅猛,组播的视频几乎到了无法直视的地步,已经不是马赛克什么的问题了,简直就是一张臭抹布。

但是上面的要求是让接收端达到1080p 16fps的播放效果,此时组播接收端的实时网络速率只有50KB/s左右,这种情况下要从软件上处理的话(因为路由器不好换),需要让组播的丢包率降低才行,但是使用iperf测了下当时网络的丢包率,能丢到80%,丢到他姥姥家?

但是此时带宽利用率却很低,赶紧换成udp单播试了一下,速度能上去,也不怎么花屏了,不清楚是不是确认机制的问题。
但是总不能说把组播换成单播,当接入的接收端变多的时候,不清楚单播效果会不会也变差。

这个时候发现了PGM,“可靠”多播协议,有不少基于PGM实现的库,打算先用windows上的写个demo出来。

想要使用PGM需要先在网络适配器上安装协议,安装完成后会在属性中出现可靠多播协议

然后就是开发了,官网文档提供的demo很棒,copy下来几乎就能跑起来。但是除了官网文档,相关资料就比较少了,头文件我还找了半天,环境上坑不少,记录一下

wsrm.h头文件

首先是windows sdk,我试了一下如果是8.1的sdk的话,是找不到wsrm.h头文件的,我有装10.0.17134.0,8.1还有10.0.15063.0三个版本的windows sdk,用everything找了一下这个头文件,得到了下面图示结果

8.1应该是没有,剩下两个版本均可以使用,更新的版本应该也行。

vs2017以上的话在visual studio installer里面修改多装个sdk就行了

传输速度

PGM本身也有发送窗口的概念,如果使用默认设置,窗口小,发送速度非常慢,每秒最多只有70KB左右,这时候需要设置socket选项
RateKbitsPerSec的单位是kilobits/s,是一个上限

    RM_SEND_WINDOW send_window;send_window.WindowSizeInBytes = 8000 * 1000;send_window.WindowSizeInMSecs = 1;send_window.RateKbitsPerSec = (send_window.WindowSizeInBytes/send_window.WindowSizeInMSecs)*8;int rc = setsockopt(s, IPPROTO_RM, RM_RATE_WINDOW_SIZE, (char *)&send_window, sizeof(send_window));if (rc == SOCKET_ERROR){cout << "setsockopt(): RM_RATE_WINDOW_SIZE failed with error code " << WSAGetLastError() << endl;}

RM_SEND_WINDOW结构体就这么三个成员,第一个是每秒速度了,第二个是发送窗口的大小,第三个是窗口大小毫秒,其中windows会强制让
RateKbitsPerSec/8 = WindowSizeInBytes * WindowSizeInMSecs

PS:WindowSzieInMSecs的值需要调整,当WindowSizeInBytes=8000并且WindowSzieInMSecs=1时,发送端较大概率会阻塞,原因未知,可能是发包速度过快导致

真的可靠么?

在文章一开始的时候可靠被加上了双引号,为的是表明这个协议并不是想象中的那么可靠。

发送窗口大小有限,如果需要恢复重传的数据在发送窗口之外了,那数据就是不可恢复的,一般当发送端速率过快接收端接收速度明显跟不上时,就会出现不可恢复现象。一旦出现不可恢复数据时,windows就会让接收端的连接重置,此时就不能继续接收。

源码

因为找不到对应的头文件让我着实头疼了很久,相关文档少,还不告诉我头文件是什么,这太不爽了,就好比让你看着门后面有啥,就是不给你钥匙。

pgm分为server端和client端,功能是发送文件,根据msdn的文档编写的

下面是server端代码

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN#include <iostream>
#include<winsock2.h>
#include<WS2tcpip.h>    //ip_mreqͷ
#include <wsrm.h>
#include <stdio.h>using namespace std;
#pragma comment(lib,"ws2_32.lib")int main() {WSADATA WSAData;WORD sockVersion = MAKEWORD(2, 2);if (WSAStartup(sockVersion, &WSAData) != 0)return 0;FILE *fp;fopen_s(&fp, "test.webm", "rb+");SOCKET        s;SOCKADDR_IN   salocal, sasession;int           dwSessionPort;s = socket(AF_INET, SOCK_RDM, IPPROTO_RM);salocal.sin_family = AF_INET;salocal.sin_port = htons(0);    // Port is ignored heresalocal.sin_addr.s_addr = htonl(INADDR_ANY);bind(s, (SOCKADDR *)&salocal, sizeof(salocal));//// Set all relevant sender socket options here////// Now, connect <entity type="hellip"/>// Setting the connection port (dwSessionPort) has relevance, and// can be used to multiplex multiple sessions to the same// multicast group address over different ports//dwSessionPort = 1234;sasession.sin_family = AF_INET;sasession.sin_port = htons(dwSessionPort);sasession.sin_addr.s_addr = inet_addr("224.4.5.6");RM_SEND_WINDOW send_window;send_window.WindowSizeInBytes = 8000;send_window.WindowSizeInMSecs = 1;send_window.RateKbitsPerSec = (send_window.WindowSizeInBytes/send_window.WindowSizeInMSecs)*8;int rc = setsockopt(s, IPPROTO_RM, RM_RATE_WINDOW_SIZE, (char *)&send_window, sizeof(send_window));if (rc == SOCKET_ERROR){cout << "setsockopt(): RM_RATE_WINDOW_SIZE failed with error code " << WSAGetLastError() << endl;}connect(s, (SOCKADDR *)&sasession, sizeof(sasession));//// We're now ready to send data!//char pSendBuffer[1400];sockaddr_in serverAddr;int iAddrlen = sizeof(serverAddr);while (1) {if (feof(fp))break;memset(pSendBuffer, 0, 1400);int data_size = fread(pSendBuffer, 1, 1400, fp);LONG        error;error = sendto(s, pSendBuffer, data_size, 0, (sockaddr*)&serverAddr,iAddrlen);if (error == SOCKET_ERROR){fprintf(stderr, "send() failed: Error = %d\n",WSAGetLastError());}}WSACleanup();return 0;
}

下面是client端代码

#include <iostream>
#include<winsock2.h>
#include<WS2tcpip.h>    //ip_mreqͷ
#include <wsrm.h>
#include <stdio.h>using namespace std;
#pragma comment(lib,"ws2_32.lib")int main() {WSADATA WSAData;WORD sockVersion = MAKEWORD(2, 2);if (WSAStartup(sockVersion, &WSAData) != 0)return 0;SOCKET        s,sclient;SOCKADDR_IN   salocal,sasession;int           sasessionsz, dwSessionPort;FILE * fp;fopen_s(&fp, "aaatest.webm", "wb+");s = socket(AF_INET, SOCK_RDM, IPPROTO_RM);//// The bind port (dwSessionPort) specified should match that// which the sender specified in the connect call//dwSessionPort = 1234;salocal.sin_family = AF_INET;salocal.sin_port = htons(dwSessionPort);salocal.sin_addr.s_addr = inet_addr("224.4.5.6");int receive_buf_size = 65536 * 10;if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&receive_buf_size, sizeof(receive_buf_size)) < 0){std::cout << "setsockopt():SO_RCVBUF failed with error code" << WSAGetLastError() << std::endl;}bind(s, (SOCKADDR *)&salocal, sizeof(salocal));//// Set all relevant receiver socket options here//listen(s, 10);sasessionsz = sizeof(sasession);sclient = accept(s, (SOCKADDR *)&sasession, &sasessionsz);if (setsockopt(sclient, SOL_SOCKET, SO_RCVBUF, (char*)&receive_buf_size, sizeof(receive_buf_size)) < 0){std::cout << "setsockopt():SO_RCVBUF failed with error code" << WSAGetLastError() << std::endl;}//// accept will return the client socket and we are now ready// to receive data on the new socket!//LONG BytesRead;char pTestBuffer[1400];sockaddr_in clientAddr;int iAddrlen = sizeof(clientAddr);while (1){memset(pTestBuffer, 0, 1400);cout << "start" << endl;BytesRead = recvfrom(sclient, pTestBuffer, 1400, 0, (sockaddr*)&clientAddr, &iAddrlen);cout << "end" << endl;if (BytesRead == 0){fprintf(stdout, "Session was terminated\n");}else if (BytesRead == -1){std::cout << "no data?!" << std::endl;}if (BytesRead > 0){fwrite(pTestBuffer, 1, BytesRead, fp);std::cout << BytesRead << std::endl;}}fclose(fp);WSACleanup();return 0;
}

转载于:https://www.cnblogs.com/lenomirei/p/11324394.html

Reliable Multicast Programming(PGM)协议相关推荐

  1. zeroMQ支持PGM协议编译

    vs2019编译 1.下载openPGM 链接:https://github.com/steve-o/openpgm 编译虽然过了但是,拿zmq epgm测试时直接报错abort参数无效.简单说就是 ...

  2. CCNA--增强型内部网关路由选择协议(EIGRP)

    一.EIGRP路由协议简介 是Cisco的私有路由协议,它综合了距离矢量和链路状态2者的优点,它的特点包括:  1.快速收敛:链路状态包(Link-State Packet,LSP)的转发是不依靠路由 ...

  3. IGRP中的RTP、Neighbor Discovery协议及Time总结

    EIGRP的运行所需要的四个组件包括: 1.Protocol-Dependent Modules(负责针对各种特定协议,如IP.IPX.APPLETALK) 2.RTP(Reliable Transp ...

  4. 深入理解IGMP协议

    IGMP网际组管理协议 ----IP多播 IGMP v1: 定义了主机只可以加入组播组,但没有定义离开成员组的信息,路由器基于成员组的超时机制发现离线的组成员. 报文格式: 版本:版本为1. 类型:1 ...

  5. 分布式系统(四) 组播 Multicast

    Multicast 组播 通信模式 Unicast 一个进程向另一个进程发送消息 尽力而为:如果信息传送,就没有被破坏 可靠的:保证信息能传送 有序:信息传送(deliver)的顺序与发送的顺序一致 ...

  6. About JXTA message reliable design

    http://www.java.net/node/684200 ------------------------------------------------------------ About J ...

  7. JMS学习十 ActiveMQ支持的传输协议

    JMS学习(ActiveMQ支持的传输协议) ActiveMQ提供了一种连接机制,这种连接机制使用传输连接器(TransportConnector)实现客户端与代理(client - to - bro ...

  8. Swift 面向协议编程 基础篇 (一) 介绍

    前言 好久没有写文章了,期末复习周也到了.在复习的同时顺便开了一个专题,面向协议编程,[ 基础篇 ],[ 进阶篇 ],[ 实践篇 ]. 介绍 首先,面向对象(OOP)大家并不陌生,苹果的很多框架都是以 ...

  9. 可靠的运输层协议,如何抵抗“剪网线”的降维打击?(rdt协议的的总结与思考)

    前言 很久没更新长文了.最近在阅读James F. Kurose和Keith Ross的<计算机网络:自顶而下方法(第6版)>第3章运输层. 题外话:Keith Ross还是Courant ...

最新文章

  1. 函数(复习),闭包,DOM
  2. 电脑硬盘是干什么用的_电脑硬盘位不够用?有了它就不担心、奥睿科硬盘柜体验...
  3. 以太网端口类型和可插拔模块揭密
  4. .net中的认证和授权(学习笔记)
  5. 今日定工资,不知是涨是跌,最迟明晚反馈
  6. 洛谷 - P1886 滑动窗口(单调队列/线段树)
  7. iOS核心动画之CALayer-自定义层
  8. pcf8523_PCF上的Spring Cloud合同和Spring Cloud Services
  9. linux系统密码正确但是一直登录不了报错Account locked due to failed logins
  10. java视频切片_使用ffmpeg视频切片并加密和视频AES-128加密后播放
  11. Java接口四个类四则运算_java 实现四则运算小程序
  12. python微信集成_python+微信+腾讯智能闲聊
  13. mahout中kmeans算法和Canopy算法实现原理
  14. css布局-瀑布流的实现
  15. android gridview 拖动排序,android可拖动排序GridView实现
  16. 盲源分离(BSS)的学习总结(PCA、ICA)
  17. 企业邮箱的优势有哪些
  18. 3、Qt5 主窗口点击按钮 弹出另一个自定义窗口
  19. 互联网+大赛评审规则浅析
  20. 求阶乘的和(C++)

热门文章

  1. 正则表达式的命名分组
  2. java timestamp是什么类型_JAVA比较2个Timestamp类型的时间大小-由此引发的思考
  3. html监控用户在线与离线,HTML5判断设备在线离线及监听网络状态变化例子
  4. python 追加到字典_使用Python读取,写入和解析JSON
  5. mysql快速随机_MySQL随机取数据最高效的方法
  6. 注入器 过检测_连云港管道检测服务
  7. matlab中degrees,Convert degrees-minutes-seconds to degrees
  8. phpmyadmin忘记mysql密码_忘记phpmyadmin密码怎么重置
  9. 串口服务器工作方式及常见异常故障问题排除方法介绍
  10. 工业交换机的日常维护保养该怎么做?