简体   繁体   中英

recvfrom function in C on Windows skips UDP data when using MinGW

I have problem with recvfrom function on Windows I cannot resolve.
See the following part of code I wrote. I run this code on Linux and Windows and I get different results in udp bitrate value.

When compiling it on Windows using Cygwin, I get the same results as on Ubuntu, what is okay. I compared this with reference tool.

When compiling it on Windows using MinGW, I get smaller upd bitrate value, which is caused by smaller number of while(1) loop iterations in one second (counter variable) and what is related - smaller amount of data captured in 1 second (data_in_1_sec variable). It seems that recvfrom funtion on Windows with using MinGW is slowest and skips udp data.
Please note that in case of upd bitrate about 0.200 Mbps results on both OS are the same using MinGW. Problem is visible on data with UDP bitrate about 20 Mbps.

Unfortunately I have to use MinGW due to fact that this code is loaded into Python code as static library. Using CygWin dll I get access violation during running this function under Python.

How to deal with this?

I use Windows 7 Professional 64.

Code I use:

while (1) {
    #ifdef _WIN32
        // start timer
        QueryPerformanceCounter(&t1);           
    #elif __linux
        clock_gettime(CLOCK_MONOTONIC, &start);
    #endif

   udp_packet_len = recvfrom(sock, udp_packet, buff_len, 0, (struct sockaddr *) &addr, &addrlen);
    #if DEBUG == 1
        counter++;
    #endif

    #ifdef _WIN32
       // stop timer
       QueryPerformanceCounter(&t2);        
    #elif __linux
       clock_gettime(CLOCK_MONOTONIC, &finish);
    #endif

   data_in_1_sec += (double)udp_packet_len;

    #ifdef _WIN32
       temp = (t2.QuadPart - t1.QuadPart);
       temp *= 1000000000.0;    
       temp /= frequency.QuadPart;
       temp /= 1000000000.0;
       second += temp;
    #elif __linux
       temp = (finish.tv_sec - start.tv_sec);
       temp += (finish.tv_nsec - start.tv_nsec) / 1000000000.0;
       second += temp;
    #endif

   if(second >=1.0) {
       processing.udp_bitrate = (((data_in_1_sec) * 8.0) /second);

        #if DEBUG == 1
            fprintf(stderr,"\nudp_bitrate: %f\n",processing.udp_bitrate);
            fprintf(stderr,"data_in_1_sec: %f\n",data_in_1_sec);
            fprintf(stderr,"second: %f\n",second);
            fprintf(stderr,"counters: %d\n",counter);
            counter = 0;
        #endif

       data_in_1_sec = 0;
       second = 0.0;
   }

Results of this code,
for Windows:

udp_bitrate: 19799823.828382
data_in_1_sec: 2505664.000000
second: 1.012399
counters: 1904

udp_bitrate: 19389475.566430
data_in_1_sec: 2451708.000000
second: 1.011562
counters: 1863

udp_bitrate: 18693904.033320
data_in_1_sec: 2367484.000000
second: 1.013158
counters: 1799

udp_bitrate: 18963187.258098
data_in_1_sec: 2399068.000000
second: 1.012095
counters: 1823

udp_bitrate: 19452989.621014
data_in_1_sec: 2459604.000000
second: 1.011507
counters: 1869

udp_bitrate: 19795284.196391
data_in_1_sec: 2509612.000000
second: 1.014226
counters: 1907

output for Ubuntu for the same data

udp_bitrate: 22016976.870087
data_in_1_sec: 2788604.000000
second: 1.013256
counters: 2119

udp_bitrate: 22022223.539749
data_in_1_sec: 2787288.000000
second: 1.012536
counters: 2118

udp_bitrate: 22003055.797884
data_in_1_sec: 2785972.000000
second: 1.012940
counters: 2117

udp_bitrate: 22041580.024322
data_in_1_sec: 2788604.000000
second: 1.012125
counters: 2119

udp_bitrate: 22025510.655441
data_in_1_sec: 2782024.000000
second: 1.010473
counters: 2114

udp_bitrate: 22412560.109513
data_in_1_sec: 2801764.000000
second: 1.000069
counters: 2129

UDP is an unreliable transport. Dropping packets is an allowed behavior, and it is to be expected where the data transmission rate exceeds the rate at which data are handled by the receiver.

Cygwin and MinGW are separate projects. They each provide their own recvfrom() wrapper built on top of the Windows kernel and API. It is conceivable that Cygwin's implementation is a bit more efficient, providing 10% greater bandwidth than MinGW's under the conditions of your test.

It may also be that your instrumentation is interfering with your measurement. At least some versions of Cygwin do not by default cause _WIN32 to be defined by the preprocessor, whereas MinGW does, so it may be that you are using clock_gettime() with Cygwin and a Windows performance counter with MinGW. You would think that Windows performance counters would have low enough overhead for such a difference to be negligible, but you are make a lot of calls to it. You should consider minimizing overhead from both sources by running the test for a fixed number of iterations and timing just the overall total for all those iterations (only one timer start/stop per rate measurement).

Bottom line: your test methodology could be improved, but even if the results are a good reflection of the behavior of the different implementations under test, they do not reveal anything fundamentally wrong.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM