1

I am porting an embedded distributed system to windows and I need to send multicast and unicast packets over loopback, I found out that for some unknown reason sending multicast takes 2x time than sending unicast.
My environment is quite simple, I have win 10 machine with 3 network cards, for the purpose of application I am using only one NIC which has two ip addresses assigned. For testing I wrote simple client and server application, client bind to first ip address(192.168.1.47) and server to second(192.168.1.46).
Client app sends 500 Ucast and 500 Mcast packets and displays average time spend in sendto() function. If client and server are started on two seperate machines both times are pretty the same but if they are started on same machine Mcast takes 2-3 times longer.
Anyone encounter a similiar problem or knows what is the reason for that? I would appriciate any hint, thanks!


Code below:

#include <iostream>
#include <winsock2.h>
#include <WS2tcpip.h>
#include <chrono>
#include <vector>
#include <numeric>

#pragma comment(lib,"ws2_32.lib") //Winsock Library

void Send(SOCKET& socket, SOCKADDR_IN& sockAddr);

int main()
{
    // Params
    char localIp[] = "192.168.1.47";
    char dstMcastAddress[] = "239.4.5.6";
    char dstUcastAddress[] = "192.168.1.46";
    int port = 5120;


    //Initialize WinSock2
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        std::cout << "WSAStartup error\r\n";
        WSACleanup();
        return -1;
    }

    // Create socket
    SOCKET sendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sendSocket == INVALID_SOCKET)
    {
        int error = WSAGetLastError();
        std::cout << "Unable to open socket " << error << std::endl;
    }

    SOCKADDR_IN localAddress;
    localAddress.sin_family = AF_INET;
    inet_pton(AF_INET, localIp, &(localAddress.sin_addr));
    if (bind(sendSocket, (SOCKADDR*)&localAddress, sizeof(localAddress)) == SOCKET_ERROR)
    {
        std::cout << "Client: bind() failed! Error: " << WSAGetLastError() << std::endl;
        closesocket(sendSocket);
        WSACleanup();
        return -1;

    }

    SOCKADDR_IN receiverUcast;
    receiverUcast.sin_family = AF_INET;
    receiverUcast.sin_port = htons(port);
    inet_pton(AF_INET, dstUcastAddress, &(receiverUcast.sin_addr));
    std::cout << "Ucast: ";
    Send(sendSocket, receiverUcast);

    SOCKADDR_IN receiverMcast;
    receiverMcast.sin_family = AF_INET;
    receiverMcast.sin_port = htons(port);
    inet_pton(AF_INET, dstMcastAddress, &(receiverMcast.sin_addr));
    std::cout << "Mcast: ";
    Send(sendSocket, receiverMcast);
}

void Send(SOCKET& socket, SOCKADDR_IN& sockAddr)
{
    char SendBuf[1000];
    std::vector<int> vec;
    int i = 0;

    while (i++ < 500)
    {
        snprintf(SendBuf, sizeof(SendBuf), "Udp client send %02d", i);

        auto start = std::chrono::system_clock::now();
        int TotalByteSent = sendto(socket, SendBuf, strlen(SendBuf), 0, (SOCKADDR*)&sockAddr, sizeof(sockAddr));
        auto end = std::chrono::system_clock::now();

        if (TotalByteSent < 0)
        {
            std::cout << "Send error\r\n";
        }
        auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
        vec.push_back(elapsed.count());
    }

    double average = std::accumulate(vec.begin(), vec.end(), 0.0) / vec.size();
    std::cout << average << std::endl;
}

Server:

#include <iostream>
#include <winsock2.h>
#include <WS2tcpip.h>
#include <chrono>
#include <vector>
#include <numeric>
#include <string_view>
#include <string>

#pragma comment(lib,"ws2_32.lib") //Winsock Library

int main()
{
    // Params
    char localIp[] = "192.168.1.46";
    char dstMcastAddress[] = "239.4.5.6";
    int port = 5120;

    char receiveBuffer[1000];

    /// Initialize WinSock2
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        std::cout << "WSAStartup error\r\n";
        WSACleanup();
        return -1;
    }

    // Create socket
    SOCKET recSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (recSocket == INVALID_SOCKET)
    {
        int error = WSAGetLastError();
        std::cout << "Unable to open socket " << error << std::endl;
    }

    // Bind to specific ip address and port
    SOCKADDR_IN receiverAddress;
    receiverAddress.sin_family = AF_INET;
    receiverAddress.sin_port = htons(port);
    inet_pton(AF_INET, localIp, &(receiverAddress.sin_addr));

    if (bind(recSocket, (SOCKADDR*)&receiverAddress, sizeof(receiverAddress)) == SOCKET_ERROR)
    {
        std::cout << "Server: bind() failed! Error: " << WSAGetLastError() << std::endl;
        closesocket(recSocket);
        WSACleanup();
        return -1;

    }

    // Join mcast group
    struct ip_mreq mreq;
    inet_pton(AF_INET, localIp, &(mreq.imr_interface.s_addr));
    inet_pton(AF_INET, dstMcastAddress, &(mreq.imr_multiaddr.s_addr));

    if (SOCKET_ERROR == setsockopt(recSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)))
    {
        std::cout << "Server: setsockopt() failed! Error: " << WSAGetLastError() << std::endl << std::flush;
        closesocket(recSocket);
        WSACleanup();
        return -1;
    }

    //Spin and wait for packets
    SOCKADDR_IN SenderAddr;
    int SenderAddrSize = sizeof(SenderAddr);
    int receivedFrames = 0;
    while (1)
    {
        int ByteReceived = recvfrom(recSocket, receiveBuffer, sizeof(receiveBuffer), 0, (SOCKADDR*)&SenderAddr, &SenderAddrSize);
        if (ByteReceived > 0)
        {
            printf("\r%04d", ++receivedFrames);
        }
        else
        {
            std::cout << "Server: recvfrom() failed! Error: " << WSAGetLastError() << std::endl;
        }
    }
}
PrzemekK
  • 11
  • 1

0 Answers0