リライアブルマルチキャストプログラミング(PGM)の信頼性を確保するための方法で、実際の一般的な信頼性の高いマルチキャスト、マルチキャスト。上位層プロトコルは、IP、TCPやUDPなどと同じレベル、トランスポート層での作業です。
ビデオプロジェクトのマルチキャスト伝送では、貧しい人々のネットワークは、マルチキャスト映像伝送性能低下が急速に、ほとんどのマルチキャストビデオにはモザイクではありません何の質問は、単に臭い雑巾である地点で直接見ることができないことが判明したとき。
しかしながら、上記要件(ルータが変更されないので)リアルタイムネットワークマルチキャスト受信終了時刻が速度のみ50キロバイト/ sであるほど、ソフトウェアから、この場合には、その後の処理、再生1080 16fpsの受信端を達成することである、と必要マルチキャストパケット損失率は、仕事のために減少したが、iperfのネットワークパケットロス率を用いて測定が80%未満であった彼の祖母を投げる、投げることができますか?
この時、帯域幅の使用率が非常に低く、かつ迅速にUDPユニキャストを交換し、それを試してみました。しかし、速度が上がることができ、またHuaping、問題が明確な確認応答メカニズムではありませんか。
しかし、我々は、受信側のアクセスは、より多くの時間となった場合、ユニキャストへのマルチキャストは、ユニキャストも悪くなる効果を知っていないと言うことはできません。
この時間は、PGM、「信頼性」のマルチキャストプロトコルは、Windows上でデモを書き出すための意図で、実装ライブラリベースPGMがたくさんありました。
PGMは、ネットワークアダプタにインストールする必要のプロトコルを使用したいインストールが完了した後、プロパティに信頼性の高いマルチキャストプロトコルが存在します
その後は、デモ文書が良いの公式ウェブサイトを提供し、開発までを実行することはほとんどできダウンコピーされます。しかし、公式サイトの文書、以下の関連情報に加えて、私も長い時間のためのヘッダファイル、環境上のピットをたくさん見つけ、それを記録
wsrm.h
ヘッダ
最初は、Windows SDKで、それは8.1のSDKである場合、私はその後、それを試してみましたが、見つけることができないwsrm.h
ヘッダファイルを、私はすべてが少しこれを見ていると、WindowsのSDKのが10.0.17134.0,8.1 10.0.15063.0 3つのバージョン、インストールされていますヘッダ、以下の結果を示します
8.1があってはならない、そして、残りの2つのバージョンが利用可能で、更新されたバージョンがOKであるべきです。
vs2017以上は、ライン上のマルチSDKをインストール内部のVisual Studioのインストーラを変更します
伝送速度
PGM本身也有发送窗口的概念,如果使用默认设置,窗口小,发送速度非常慢,每秒最多只有70KB左右,这时候需要设置socket选项
WindowSizeInBytes
的单位是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
时,发送端较大概率会阻塞,原因未知,可能是发包速度过快导致
源码
因为找不到对应的头文件让我着实头疼了很久,相关文档少,还不告诉我头文件是什么,这太不爽了,就好比让你看着门后面有啥,就是不给你钥匙。
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 here
salocal.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 * 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;
}
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;
}