Reliable Multicast Programming(PGM)协议

Reliable Multicast Programming (PGM) Actual common reliable multicast, multicast in a way to ensure reliability. Upper layer protocol is IP, TCP and UDP as well as the same level, work in the transport layer.

In the multicast transmission of video project, found that when poor network, multicast video transmission performance decline rapidly, almost to the multicast video can not look directly at the point where the question of what is not a mosaic, is simply a smelly rag .

However, the above requirement is to achieve the receiving end of playback 1080p 16fps, real-time network multicast reception end time the rate is only 50KB / s or so, from the software, then the processing in this case (since the router not change), need to multicast packet loss rate decreased for the job, but iperf measured using a network packet loss rate was under 80% can throw, throw his grandmother?

But this time bandwidth utilization is very low, and quickly replaced udp unicast tried it, the speed can go up, nor how Huaping, the problem is not clear acknowledgment mechanism.
But we can not say that the multicast into unicast, when the access of the receiving end becomes more time, do not know the effect Unicast will also deteriorate.

This time found the PGM, "reliable" multicast protocols, there are a lot of library-based PGM implemented, with the intention to write out a demo on the windows.

PGM want to use protocols need to be installed on the network adapter, there will be a reliable multicast protocol in the property after the installation is complete

Then it is developed, demo document provides a good official website, copy down almost able to run up. But in addition to the official website documents, relevant information on less, and I also find the header file for a long time, a lot of pits on the environment, record it

wsrm.hhead File

The first is the windows sdk, I tried it if it is sdk 8.1, then, can not find wsrm.hthe header file, I have installed 10.0.17134.0,8.1 there 10.0.15063.0 three versions of windows sdk, with everything looking a bit this header, illustrating the results obtained below

8.1 should not be, and the remaining two versions are available, updated version should be OK.

More than vs2017 then modify the inside visual studio installer installing a multi-sdk on the line

transfer speed

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;
}

Guess you like

Origin www.cnblogs.com/lenomirei/p/11324394.html