This is the mail archive of the cygwin@sourceware.cygnus.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: select()


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]