This is the mail archive of the
cygwin@sourceware.cygnus.com
mailing list for the Cygwin project.
Re: select()
- To: gnu-win32 at cygnus dot com
- Subject: Re: select()
- From: "Todd M. Grimm" <grimm at itd dot nrl dot navy dot mil>
- Date: Fri, 9 Oct 1998 09:20:49 -0400 (EDT)
- cc: Michael Czapski <MCzapski at openplus dot com dot au>, Harry Broomhall <haeb at demon dot net>
On Wed, 7 Oct 1998, Todd M. Grimm wrote:
> I am using select() to test whether there are bytes on a socket to read
> without blocking my program to check on this.
>
> The problem is that even when there is no data it returns a 1 to say that
> there is data. This causes my program to try a read which blocks because
> there really is no data.
>
> I saw several messages in the archives of this list about this, but all I
> could find were questions. No one ever seemed to answer the question.
>
> Please let me know if you know how to get select() to work right or if
> there is a nother way to test for bytes without blocking.
Thanks to Harry and Michael for their responses. Above is my original
notes. I am still having problems.
I have isolated two small .C files that demonstrate what I am doing (wrong).
I am hopeful that they will help one of you to spot my problem or confirm
that you have the same problem.
I am running on Windows NT 4.0 using B19 of the Cygwin g++. I am using
version 19.1 of the dll file. 19.0 and 19.4 have the same problem. With
19.4 my bash shell failed to read .bashrc so I gave up on that.
So, attached is the code. The first file describes how to run it. There are
compile statements in their respective files.
Thanks a bunch (I am really stuck),
Todd
// ---------------------------------------- begin file SimpleServer.C
// compile command: gcc -o SimpleServer SimpleServer.C -lstdc++
// test instructions:
//
// 1. compile both this file and the SimpleClient.C
// 2. run SimpleServer first in a bash or DOS window
// 3. run SimpleClient in another bash or DOS window
// 4. they connect and SimpleClient starts sending messages/sleeping
//
// 5. SimpleServer hangs in a select even though data is available
// until you press any key in its window (even shift or ctrl
// or alt will do)...see also notes at the close(0) call below
//
// 6. once "unhung," SimpleServer always gets a return value of
// one from select() even when there is no data, thus it always
// proceeds to the read call where it blocks
//
// BOTTOM LINE: I need select() to block because I want to use
// the timeout version below in order to wait for data but
// "come up for air" every so many seconds to do some other
// stuff...if select() always returns I cannot get my waiting
// period as desired.
#include <stdio.h>
#include <fstream.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#ifdef WINNT
#define __attribute__(x)
#include <Windows32/Base.h>
#include <Windows32/Sockets.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
// constants
#define PORT 2001
// globals for this file
static int fd = -1;
static void print_fd_set(char *msg, fd_set set)
{
cerr << msg << " ---- fd_count=" << set.fd_count << endl;
if (set.fd_count > FD_SETSIZE) { cerr << "fd_count invalid" << endl; return; }
for (int i = 0; i < set.fd_count; i++)
cerr << "fd_array[" << i << "]=" << set.fd_array[i] << endl;
}
int non_block_select(void)
{
struct fd_set fdbits;
FD_ZERO(&fdbits);
FD_SET(fd, &fdbits);
print_fd_set("after set", fdbits);//zzz
struct timeval interval; interval.tv_sec = 0; interval.tv_usec = 0;
int fds_ready = select(fd+1, &fdbits, (fd_set*) NULL, (fd_set*) NULL, &interval);
cerr << "NB-----------------------------------------------------select() returned " << fds_ready << endl;
print_fd_set("after select", fdbits);//zzz
//sleep(1);
// this seems to correctly reveal the number of bytes ready at all times
//long unsigned ioctlval = 9999;
//int retval = ioctl(socketPrep.fd, FIONREAD, &ioctlval);
//cerr << "bytes ready=" << ioctlval << "\tioctl retval=" << retval << endl;//zzz
return fds_ready;
}
int timeout_select(int seconds)
{
struct fd_set fdbits;
FD_ZERO(&fdbits);
FD_SET(fd, &fdbits);
print_fd_set("after set", fdbits);//zzz
struct timeval interval; interval.tv_sec = seconds; interval.tv_usec = 0;
int fds_ready = select(fd+1, &fdbits, (fd_set*) NULL, (fd_set*) NULL, &interval);
cerr << "TO-----------------------------------------------------select() returned " << fds_ready << endl;
print_fd_set("after select", fdbits);//zzz
return fds_ready;
}
int block_select(void)
{
struct fd_set fdbits;
FD_ZERO(&fdbits);
FD_SET(fd, &fdbits);
//print_fd_set("after set", fdbits);//zzz
int fds_ready = select(fd+1, &fdbits, (fd_set*) NULL, (fd_set*) NULL, (struct timeval *) NULL);
cerr << "B------------------------------------------------------select() returned " << fds_ready << endl;
//print_fd_set("after select", fdbits);//zzz
return fds_ready;
}
void init(void)
{
// use both of these and we do not need the "keypress" to
// free things up initially, but select always returns -1 then
//close(0); //zzz just this and it still needs a "shift press" to free it up, and needs it repeatedly
//close(1); //zzz just this and it dies
struct sockaddr_in addr;
memset((char *) &addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(PORT);
cerr << "connecting via port " << PORT << endl;
int sock = socket(AF_INET, SOCK_STREAM, 0); // create socket
if (sock<0) { perror("creating socket"); exit(-1); }
if (bind(sock, (struct sockaddr*) &addr, sizeof(addr))) { perror ("binding socket"); close(sock); exit(-1); }
if (listen(sock, 1)) { perror ("listening to socket"); close(sock); exit(-1); }
struct sockaddr remote;
int remote_len = sizeof(remote);
if ((fd = accept(sock, &remote, &remote_len)) == -1) { perror("accepting socket"); close(sock); exit(-1); }
cerr << "server side connected" << endl;
close(sock);
cerr << "fd=" << fd << endl;//zzz
cerr << "fd modes=" << (void*) fcntl(fd, F_GETFL) << endl;//zzz
}
int main (int argc, char **argv)
{
char buff[1000];
init(); // open the socket
while(1)
{
cerr << "calling block_select()" << endl;
block_select();
cerr << "back from \"select()\" and going on to read" << endl;
int bytesread = read(fd, buff, (size_t) 999);
if (bytesread == 0) break;
buff[bytesread] = 0;
cerr << "read this #" << buff << "#" << endl;
}
cerr << "got eof" << endl;
}
// ---------------------------------------- end file SimpleServer.C
// ---------------------------------------- begin file SimpleClient.C
// compile command: gcc -o SimpleClient SimpleClient.C -lstdc++
// see test instructions in SimpleSerevr.C
#include <stdio.h>
#include <fstream.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#ifdef WINNT
#define __attribute__(x)
#include <Windows32/Base.h>
#include <Windows32/Sockets.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
// constants
#define PORT 2001
// globals for this file
static int fd;
void init(void)
{
struct sockaddr_in addr;
memset((char *) &addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(PORT);
cerr << "connecting via port " << PORT << endl;
fd = socket(AF_INET, SOCK_STREAM, 0); // create socket
if (fd<0) { perror("creating socket"); exit(-1); }
if (connect(fd, (struct sockaddr*) &addr, sizeof(addr))) { perror ("socketPrep - connecting socket"); exit(-1); }
cerr << "socketPrep - client side connected" << endl;
}
int main (int argc, char **argv)
{
char buff[1000];
buff[0] = 'A';
buff[1] = 0;
init(); // open the socket
cerr << "sending first message in 5 seconds" << endl; sleep(5);
while(1)
{
int len = strlen(buff);
write(fd, buff, len);
cerr << "sent this #" << buff << "#" << endl;
buff[len] = 'x';
buff[len+1] = 0;
cerr << "sleeping" << endl;
sleep(10);
}
}
// ---------------------------------------- end file SimpleClient.C