Hi Glenn

Thanks for the reply, so more below

> > Hi all
> >
> > Using AF_UNIX/SOCK_DGRAM with current version (3.2.0) seems to drop  
> > messages or at least they are not received in the same order they are  sent
> >
> > Attached C:ish (with C++ threads though) sample program that  essentially 
> > creates a "client" that writes as much as possible and a  "server" that 
> > consumes as much as possible
> >
> > It seems like some buffer is filled and then messages are dropped (or at 
> > least it appears so) (if someone is about to test this, the "sleep" might 
> > need to be adjusted in order to make this happen)
> >
> > Hopefully it's just a flaw in our application (and sample), but as far as 
> > we can see, this should work
> >
> >
> > Does anyone, perhaps named Ken, have any insightful thoughts about this ?
> 
> 
> > const int size = BUFSIZ * 2;
> 
> 
> >     char buffer[size] = {};
> >
> >     for( int idx = 0; idx < count; ++idx)
> >     {
> >         memcpy( buffer, &idx, sizeof idx);
> >
> >         const ssize_t result = sendto( fd, buffer, size, 0, (struct
> > sockaddr*)&address, sizeof address);
> 
> 
> >             const ssize_t result = recv( fd, buffer, size, 0);
> ...
> >             int index = 0;
> >             memcpy( &index, buffer, sizeof idx);
> 
> This appears to be a programming error, unrelated to Cygwin.
> 
> I know that what you provided was an example test case, but you might want  
> to check if your app is sending way too much when the actual payload size is 
> much smaller.  In the example you provided, you are sending 16KB instead of 4 
> bytes for the count.

To send a larger buffer (in this case 16 KB) is intentional, but just the 
sizeof int is relevant. The reason is just to send many bytes and verify that 
they end up on the other side in correct order


> Is your code handling partial read/recv and partial write/sendto?  (It is 
> definitely a bug in the use of recv() in the sample code.) 

It was not and the updated version does not either, but that is not the issue 
though but I added a test to verify that the whole chunk is sent/read

> Partial reads and writes can occur more frequently with non-blocking sockets, 
> but it is still good defensive programming to detect and handle partial 
> read/writes.

That might be the case, but this is blocking attempts though (or maybe I've 
misunderstood the flags ?), but regardless of that, the test-case is not about 
how to handle partial writes/reads though, but to kind of show that messages 
seems to be lost, but of cource code need not to be flawed so thanx for the 
feedback

It almost seems like it is UDP-semantics and that packages can get lost or end 
up in non sequential order, and of course SOCK_DGRAM tells you that, but the 
posix description says "UNIX domain datagram sockets are always reliable and 
don't reorder datagrams"

It seems like when an internal buffer or so of 64 KB is filled the rest of the 
packages are dropped until consumed, so in this case the 32 first packages 
arrive in correct order but after that any random package (with index > 32) 
seems to end up at the "server"

> It goes without saying that if your protocol sends a fixed size chunk of 
> data, that you should ensure that you read the entire fixed size, even if 
> only using part of the data.

That's done in the updated version, or at least verified

> Cheers, Glenn

Best regards,
Kristian
#include <sys/socket.h>
#include <sys/un.h>

#include <unistd.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <thread>
#include <chrono>


// $ g++ --std=gnu++17 af_unix.cpp

const char* const path = "address";
const int count = 1000;
const int size = BUFSIZ * 2;

int client()
{
    const int fd = socket( AF_UNIX, SOCK_DGRAM, 0);

    if( fd == -1)
    {
        perror( "socket error");
        return -1;
    }

    struct sockaddr_un address{};

    strcpy( address.sun_path, path);
    address.sun_family = AF_UNIX;

    char buffer[size] = {};

    for( int idx = 0; idx < count; ++idx)
    {
        memcpy( buffer, &idx, sizeof idx);

        const ssize_t result = sendto( fd, buffer, size, 0, (struct 
sockaddr*)&address, sizeof address);

        if( result == -1 || result != size)
        {
            perror( "sendto error");
            return -1;
        }
    }

    close( fd);
    return 0;
}

int server()
{
    const int fd = socket( AF_UNIX, SOCK_DGRAM, 0);

    if( fd == -1)
    {
        perror( "socket error");
        return -1;
    }

    struct sockaddr_un address{};

    strcpy( address.sun_path, path);
    address.sun_family = AF_UNIX;

    const int result = bind( fd, (struct sockaddr*)&address, sizeof address);

    if( result == -1)
    {
        perror( "bind error");
        return -1;
    }

    return fd;
}

int main( int argc, char* argv[])
{
    const int fd = server( );

    if( fd != -1)
    {
        fprintf( stdout, "%d\tnumber of packages\n", count);
        fprintf( stdout, "%d\tbytes per package\n", size);

        std::thread{ [&](){client( );}}.detach();

        std::this_thread::sleep_for( std::chrono::microseconds( 500));
    
        char buffer[size] = {};

        for( int idx = 0; idx < count; ++idx)
        {
            const ssize_t result = recv( fd, buffer, size, 0);

            if( result == -1 || result != size)
            {
                perror("recv error");
                unlink( path);
                return -1;
            }

            int index = 0;
            memcpy( &index, buffer, sizeof idx);

            if( index != idx)
            {
                fprintf( stderr, "expected %d but got %d\n", idx, index);
                unlink( path);
                return -1;
            }
        }

        close( fd);
        unlink( path);
    }

    return 0;
}
--
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple

Reply via email to