LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-02-2012, 12:20 PM   #1
jonshouse
LQ Newbie
 
Registered: Jan 2012
Posts: 9

Rep: Reputation: Disabled
Linux udp broadcast socket wierdness


Hi people, not sure this is the best place to ask but I will give it a go.

I've written some code destined for an embedded system but currently running on PCs to broadcast audio around a network.

Two processes run in parallel on each PC, an encoding process called tx and a receiving process called rx.

The tx process reads audio from pulse and sends it as UDP broadcast packets about the rate of 40 packets a second.

The rx processes sets up a UDP socket, sets it to O_NONBLOCK. It then reads packets as fast as possible, each packet of audio is passed to pulse to be played. All seems to work, so far so good.

The weirdness is with the behaviour of "recvfrom". If I run the rx process first then recvfrom returns a mixture of -1 (EAGAIN) and the size of the received packet, it does not block. If I run the tx process, then start the receive process second then "recvfrom" blocks and only returns the size of packets.

For example if I print the result of "revcfrom", starting rx process first gives.

-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1

Then I start the TX process I now get

-1 -1 -1 -1 1024 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1024

All correct so far.

But start the transmitting process first, then run rx. I now get
1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024

IE "recvfrom" is now blocking !

Anyone any ideas what i'm doing wrong ?
Thanks,
Jon
 
Old 01-02-2012, 05:20 PM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
It would be helpful to see how your client (receiver) is managing the call to recv_from(), and the surrounding code around it.

Personally, I do not see the purpose of setting up a UDP socket to be non-blocking. I tend to use select() to determine if there is activity on the socket (ie something needs to be read), and if I need to perform additional duties while the socket is idle, then I specify a timeout for the select(). Handling a return value of -1 and an errno of EAGAIN in a loop doesn't seem very prudent.
 
Old 01-03-2012, 12:14 AM   #3
jonshouse
LQ Newbie
 
Registered: Jan 2012
Posts: 9

Original Poster
Rep: Reputation: Disabled
Code snippets

Hi, thanks for the reply.

I initialise the socket on the receiving process like this:

Code:
udp_setup_socket(char *myipaddress,int listen)
{
        // Open socket
        udpsockfd = socket(PF_INET, SOCK_DGRAM, 0);
        if (udpsockfd<0)
        {
                perror("error, could not create socket");
                exit(1);
        }
        printf("%s: Socket created\n",PROGNAME);
        fflush(stdout);

        // Setuop socket, specify listening interfaces etc
        recvaddr.sin_family = AF_INET;
        recvaddr.sin_port = htons(PORT+conversation);
        recvaddr.sin_addr.s_addr = INADDR_ANY;
        memset(recvaddr.sin_zero,'\0',sizeof (recvaddr.sin_zero));

        // Put socket in non blcoking mode
        int flags = fcntl(udpsockfd, F_GETFL);                                          // Get the sockets flags
        flags |= O_NONBLOCK;                                                            // Set NONBLOCK flag
        if (fcntl(udpsockfd, F_SETFL, flags) == -1)                                     // Write flags back
        {
                perror("error,fcnctl failed - could not set socket to nonblocking");
                exit(1);
        }

        // Bind to socket, start socket listening
        if (listen==TRUE)
        {
                if(bind(udpsockfd, (struct sockaddr*) &recvaddr, sizeof (recvaddr)) == -1)
                {
                        perror("bind failed, only one process can bind at a time");
                        exit(1);
                }
                fprintf(stderr,"%s: Listening for UDP data on port %d \n",PROGNAME,PORT+conversation);
                fflush(stderr);
        }
}


and read it with this function:


Code:
// Receive a single UDP frame if available
int udp_receive (char *originating_ip, int verbose, int hexdump)
{
        //struct sockaddr_in recvaddr;                                                  // An IP address record structure
        int c,i;
        unsigned int offs;
        int numbytes;
        int addr_len;

        addr_len = sizeof(recvaddr);
        numbytes = recvfrom (udpsockfd, udpbuffer, 1024, 0, (struct sockaddr *) &recvaddr, &addr_len);
        //printf("%d ",numbytes);  fflush(stdout);

        if (numbytes>0)
        {
                sprintf(originating_ip,"%s",inet_ntoa(recvaddr.sin_addr));
                if (verbose==TRUE)                                                      // If chatty is true show receipt of packets
                {
                        printf("%s: received %d bytes from %s via UDP port %d  ",PROGNAME,numbytes,originating_ip,PORT+conversation);
                        fflush(stdout);
                }

                if (hexdump==TRUE)                                                      // If dump is true show packets as hexdump
                {
                        if (verbose==TRUE)
                                printf(" Dumping contents\n");
                        c=0; offs=0;
                        printf("%04X: ",offs);
                        for (i=0;i<numbytes;i++)
                        {
                                //printf("%c",udpbuffer[i]);                            // ASCII
                                printf("%02X ",udpbuffer[i]);                           // HEX
                                c++;
                                if (c==16)
                                {
                                        offs=offs+16;
                                        c=0;
                                        printf("\n%04X: ",offs);
                                        fflush(stdout);
                                }
                        }
                        printf("\n");
                }
                return(TRUE);
        }
        return(FALSE);
}



Code:
    while (quit!=TRUE)
    {
        if (udp_receive(originating_ip,FALSE,FALSE)==TRUE)
        {
            process packet
What I fail to understand is why changing the order in which the processes start seems to change the blocking behaviour of recvfrom ? Why would I need to use select() to insert and extra poll before a function that should simply never block ? I guess i'm failing to understand something subtle ...

Thanks for your help.
Jon

Last edited by jonshouse; 01-03-2012 at 12:18 AM.
 
Old 01-03-2012, 06:25 AM   #4
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Unfortunately, I cannot glean anything from the code you presented; it looks ok. I have a few question though...

1. What is the value of 'listen' when your rx (receiver) calls upd_setup_socket()?
2. What is the value of myipaddress within udp_setup_socket()?

Quote:
Originally Posted by jonshouse View Post
Why would I need to use select() to insert and extra poll before a function that should simply never block ? I guess i'm failing to understand something subtle ...
By default, recvfrom() blocks. If you setup the socket to be non-blocking, then it shouldn't wait to receive data. If you attempt to receive data when there isn't any to be read, then a non-blocking socket will report an error with errno set to EAGAIN (or equivalently EWOULDBLOCK).

I personally use select() to know when it is appropriate to receive on the socket. I use non-blocking setup very sparingly, and when I do, it is for a TCP socket (to mimic a stream), not a UDP socket which is used to receive whole datagrams.

I do not have enough information about your applications to determine if it is merely a speed issue, or some other subtle issue with the code. You undoubtedly must have some setup that governs how often the the rx code attempts to read using recvfrom(), otherwise I would suspect that it would flood the terminal with error messages.
 
Old 01-03-2012, 01:11 PM   #5
jonshouse
LQ Newbie
 
Registered: Jan 2012
Posts: 9

Original Poster
Rep: Reputation: Disabled
Fixed

I found the issue, it was nothing to do with sockets at all ! DOH !
What I thought was a blocking behaviour in recv_from() was actually a blocking behaviour in the pulse audio code causing recv_from to always have pre-buffered data available. Seems pulse audio pa_simple_write() does not block unless the audio buffers are full, then it suddenly starts to block for a long period, odd. Data is generated at the same rate it played so I don't quite understand what is going on .. ho hum ...

The "myipaddress" pointer was stale code, i've removed it :-)

The reason for a non-blocking udp socket is that 8 sources are sending 44 1k Byte packets a second, so recv_from needs to pick up 352 1k frames of data per second and well as pipe those into 8 connection to pulse audio for playback. Not a struggle for a PC but I have my doubts this going to be as simple when ported to arm and Wifi ...

Thanks for the help,
Jon
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
broadcast (udp) socket - multi processes emarri Programming 1 09-25-2006 06:06 AM
udp broadcast from one subnet to another thru a linux router siva_bhavani Linux - Networking 1 12-30-2004 10:20 AM
How to receive UDP and ICMP packets, by one UDP socket(PMTUD) myself_rajat Linux - Networking 0 05-28-2004 05:43 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:37 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration