non-blocking accept(3I) wanted. (ISC's tcp/ip)

Hans Bayle hansb at aie.uucp
Thu Apr 25 23:56:18 AEST 1991


I have a little problem with the tcp/ip package that comes with
Interactive Unix System V 386/ix.
The manual says that when calling accept(3I) is done with the
file descriptor (in this case a socket) set to non-blocking,
that accept() will return immediately even when there are no pending
connections present on the queue. In that case it should return
EAGAIN. I isolated the problem in the two following tiny programs:

A server:

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

main()
{
  int on=1;
  int s, r, ns, length;
  char buf[BUFSIZ];
  char hostname[128];
  struct sockaddr_in server;
  struct sockaddr_in client;
  FILE *fin;
  struct hostent *hp, *gethostbyname();

  if (gethostname(hostname, sizeof hostname) == -1) {
  	perror("gethostname failed");
	exit(1);
  }
  /* get host by name from nameserver */
  if((hp= gethostbyname(hostname)) < 0) {
	perror("client: gethostbyname failed");
	exit(1);
  }

  printf("\n\nServer started on %s\n\n", hp->h_name);

  /* initialize adress struct */
  bzero((char *) &server, sizeof(server));
  bcopy(hp->h_addr, &server.sin_addr, hp->h_length);
  server.sin_port= htons(2000);
  server.sin_family= hp->h_addrtype;
  server.sin_addr.s_addr= INADDR_ANY;

  /* create a new socket */
  if((s=socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) {
	perror("server socket failed");
	exit(1);
  }

  if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) < 0) {
	perror("Server: setsockopt failed");
    exit(1);
  }


  if((r=bind(s, &server, sizeof(server))) < 0) {
	perror("Server: bind failed");
	exit(1);
  }


    if((r=listen(s, 5)) < 0) {
	  perror("Server: listen failed");
	  exit(1);
    }
  fprintf(stderr, "listen\n");

  for(;;) {
  
    length= sizeof(client);

    /* as you see, i'm using fcntl to set the socket non_blocking.... */
    fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0) | O_NDELAY);
    ns=accept(s, &client, &length);

    fprintf(stderr, "accept\n");

    if (ns != -1) {
	bzero(buf, BUFSIZ);
	while((r= read(ns, buf, BUFSIZ)) > 0) {
	  buf[r]= '\0';
      
	  if((r=write(ns, "ACK\n", 4)) < 0)
	    perror("Server: write ACK failed");
	  else
	    printf("Received %s", buf);
	  bzero(buf, BUFSIZ);
	}
    } else {
	  if (ns == EAGAIN) {
		printf("No clients....\n");
		sleep(5);
          } else {
	      perror("Server: accept failed");
	      exit(1);
	  }
    } 
    close(ns);
    fprintf(stderr, "end read\n");
  }
}


To access the server a client:


#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

main(argc,argv)
int argc;
char **argv;
{
  int on=1;
  int s, r, ns, length;
  char buf[BUFSIZ];
  char hostname[128];
  struct sockaddr_in client;
  struct hostent *hp, *gethostbyname();

  if (argc != 2) {
	printf("Wrong host name.\n");
	exit(1);
  }

  /* get host by name from nameserver */
  if((hp= gethostbyname(argv[1])) < 0) {
	perror("client: gethostbyname failed");
	exit(1);
  }
  printf("Client trying to connect to %s\n", hp->h_name);

  /* initialize adress struct client */
  memset((char *)&client, '\0', sizeof(client));
  memcpy((char *)&client.sin_addr, hp->h_addr, hp->h_length);

  client.sin_port= htons(2000);
  client.sin_family= hp->h_addrtype;

  /* create a new socket */
  if((s=socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) {
	perror("client socket failed");
	exit(1);
  }

  if((r=connect(s, &client, sizeof(client))) < 0) {
	perror("client connect failed");
	exit(1);
  }

  bzero(buf, BUFSIZ);
  r= read(0, buf, BUFSIZ);
  if((r=write(s, buf, r)) < 0) {
    perror("client write failed");
    exit(1);
  }
  bzero(buf, BUFSIZ);
  if((r=read(s, buf, BUFSIZ)) >= 0) {
      if(strncmp(buf, "ACK", 3)!= 0) {
        buf[r-1]= '\0';
        printf("Received %s, instead of ACK\n", buf);
      }
  }
  else
      printf("No response\n");
}


The problem is that accept() in the server just blocks, even with the
fcntl() call..
Is this a bug in the lib, the manual or in my program?



More information about the Comp.unix.sysv386 mailing list