From: Dan Johnston (dan.johnston++at++nrc.ca)
Date: 08/23/2004 12:13:45
"Kevin C. Chao" wrote:
> Hi,
>
> I am trying to use non-blocking UDP sockets in my performer application but
> could not get it to work.
> I am able to make the blocking UDP working. When I change it to non-blocking
> mode with "ioctl(sid, FIONBIO, ...);", my recvfrom() returns immediately
> with -1 (i.e. no data is read to the buffer).
>
> How do I fix this? Thanks.
>
> Kevin
>
Well... you can't. When the socket is non-blocking then recvfrom will
always return immediately (unless you set a time delay). You must
check the error code from recvfrom.
Here is some code pieces for how I do it...
I create my socket(s) like this....
/* X input done, now initialize the datagram sockets */
if( chan == 0 )
{
/* create control socket */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if ( sock < 0)
{
pfNotify(PFNFY_FATAL, PFNFY_RESOURCE,
"openXSocketInput() Can't open datagram socket");
return;
}
if( blocking_mode == NONBLOCKING )
/* set the socket to be non-blocking */
if( fcntl( sock, F_SETFL, FNDELAY ) < 0 )
{
pfNotify(PFNFY_FATAL, PFNFY_RESOURCE,
"openXSocketInput() Can't set datagram socket to non-blocking");
return;
}
/*just in case, clear the address struct */
bzero( (void *)&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
/* The constant INADDR_ANY tells the system
* that we will accept a connection from any
* Internet interface on the system.
*/
/* Assign server port number */
server.sin_port = socketData->controlPortNumber;
/* name the socket - I don't know why this is required, but it is */
if (bind(sock, (struct sockaddr *)&server, sizeof server) < 0 )
{
pfNotify(PFNFY_FATAL, PFNFY_RESOURCE,
"openXSocketInput() Can't bind the datagram socket");
return;
}
/* pass on the socket for communications */
socketData->controlSocket = sock;
/* all done sockets - set the flags to say we are ready */
} /* end of if chan == 0 */
Then I set the socket to 'interupt' when it is ready...
/* we only do this (check for sockets) if input is default */
if( chan == 0 )
{
/* look for any socket events or X11 events */
/* The old method was to block waiting for an X11 event, then
* go get it. Now we have to check for (one of several)
* network/socket events OR an X11 event. The selected way
* (pun intended) is an interrupt-like 'select' method to
* do a blocking wait from any source.
*/
/* set up the file descriptors */
FD_ZERO( &inputFDSet );
/* the X11 input stream */
fdX11 = ConnectionNumber( DeviceInput->ichan[chan].dsp );
FD_SET( fdX11, &inputFDSet );
/* the standard keyboard/mouse emulating socket stream */
FD_SET( socketData->controlSocket, &inputFDSet );
/* if set, the optional user socket stream */
if( socketData->userDefinedSocket > 0 )
FD_SET( socketData->userDefinedSocket, &inputFDSet );
/* now use 'switch' function to wait (forever) until some
* input is ready
*/
switch (select(FD_SETSIZE, &inputFDSet, (fd_set *)NULL,
(fd_set *)NULL, NULL))
{
case 0: /* timeout should never happen! */
pfNotify(PFNFY_FATAL, PFNFY_RESOURCE,
"mpXInput() unexpected timeout!");
perror("select error");
break;
case -1: /* Error, should call select again */
pfNotify(PFNFY_FATAL, PFNFY_RESOURCE,
"mpXInput() select error!");
perror("select error");
break;
default: /* Data is ready */
/* find out which file descriptor is ready */
if (FD_ISSET(socketData->controlSocket, &inputFDSet))
{
/* control socket is ready to be read from. */
/* read (should be ready!) control input events */
i = recvfrom( socketData->controlSocket, data_buffer,
MAX_MESSAGE_SIZE, 0, 0, 0 );
if( i < 0 )
{
pfNotify(PFNFY_FATAL, PFNFY_RESOURCE,
"mpXInput() Can't read control datagram socket");
perror("recvfrom error");
exit(1);
}
/* process the socket message (terminate string) */
data_buffer[i] = '\0';
collectXSocketInput(chan, data_buffer);
}
else if (FD_ISSET(socketData->userDefinedSocket, &inputFDSet))
{
/* user defined socket is ready to be read from. */
/* read the (should be ready!) user socket input events */
i = recvfrom( socketData->userDefinedSocket,
socketData->dataBufferUser,
MAX_USER_MESSAGE_SIZE, 0, 0, 0 );
if( i < 0 )
{
pfNotify(PFNFY_FATAL, PFNFY_RESOURCE,
"mpXInput() Can't read user datagram socket");
perror("recvfrom error");
exit(1);
}
/* we have a user message - store it */
socketData->dataBufferUser[i] = '\0';
socketData->dataLengthUser = i;
}
else /*(FD_ISSET(fdX11, &read_template)) */
{
/* do a blocking check for X11 events and process
* them if any
*/
XPeekEvent(DeviceInput->ichan[chan].dsp, &event);
collectXSocketInput(chan, NULL);
}
break;
} /* end switch */
}
else /* if chan = 0 */
{
/* for non-default channels do the normal X11 input */
XPeekEvent(DeviceInput->ichan[chan].dsp, &event);
collectXSocketInput(chan,NULL);
}
Notice that when the 'select' function indicates that the datagram
socket is ready, only then do I call recvfrom to grab the message
and call another routine to process it.
On Win32 you have to do even more. I had to create a 'pseudo'
window to receive the socket events.
Good luck!!
--
___|__ |
/ | \ ||\ Daniel (Dan) Johnston
/___|___\ || \ Dan.Johnston++at++nrc.gc.ca
_____|____ || \ National Research Council of Canada, London, ON
| | | || \ Integrated Manufacturing Technologies Institute
\___| | | ||____\ Tel: (519) 430-7081 Fax: (519) 430-7090
\_o_\___|____|_|______\_ Inst: http://www.nrc.gc.ca/imti
\ o / These opinions are my own! Not those of NRC.
\________________/ Virtual Reality:
http://www.nrc.ca/imti/vetc/home.html
More Tall Ships - Fewer Computers!
This archive was generated by hypermail 2b29 : Mon Aug 23 2004 - 12:19:00 PDT