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