arup@grad1.cis.upenn.edu (Arup Mukherjee) (02/14/89)
To all net.wizards [again...] : I had 3 responses to my earlier posting asking how to obtain a FILE * that would allow bidirectional communication over an internet socket. Well, I had 3 responses and they all suggested that I dup() the fd and use one for reading and the other for writing. As I indicated in my earlier posting, this does not work. Enclosed below are two program listings. writer.c waits for a connection, writes some stuff to it, and then trys to read something. reader.c connects to the write, reads some stuff and then writes some stuff. These work fine using read() and write() calls. However, when I substitute equivalent fprintf and fscanf calls (by using -DPRINTF or -DSCANF from the command line while compiling), nothing works. Again, any suggestions will be greatly appreciated.... Arup Mukherjee [arup@grasp.cis.upenn.edu] ---writer.c--- # include <stdio.h> # include <sys/types.h> # include <sys/socket.h> # include <sys/errno.h> # include <netinet/in.h> # include <netdb.h> int sock, i, newsock, j, sock2; char *ptr; char buf[1024]; char *buf2; extern int errno; cleanup () { shutdown(sock, 2); shutdown(sock2, 2); shutdown (newsock, 2); printf ("writer : exiting\n"); exit(0); } main (argc, argv) char **argv; { struct sockaddr_in sa; struct hostent *host; FILE *in, *out; host = (struct hostent *) gethostbyname("localhost"); bzero (&sa, sizeof(struct sockaddr_in)); sa.sin_family = AF_INET; bcopy (host->h_addr, &sa.sin_addr, host->h_length); sa.sin_port = 7000; sock = socket (AF_INET, SOCK_STREAM, 0); bind (sock, &sa, sizeof(struct sockaddr_in)); perror ("bound socket..."); listen (sock, 3); newsock = accept(sock, &buf2, &j); fprintf (stderr,"writer : Connected %s %d : %d\n", buf2, j, newsock); for (i = 0; i< 20; ++i) signal (i, cleanup); sock2 = dup(newsock); out = fdopen (newsock, "w"); in = fdopen (sock2, "r"); for (i=0;i < 3;i++){ errno = 0; sprintf (buf, "Testing : %d", i); # ifdef PRINTF fprintf(out, "%s\n", buf); # else write (newsock, buf, strlen(buf) + 1); # endif if (errno) perror("Writer Error :"); } # ifdef SCANF fscanf(in, "%s", buf); # else read (newsock, buf, 30); # endif fprintf(stderr, "writer reads: %s\n", buf); cleanup(); } --- reader.c --- # include <stdio.h> # include <sys/types.h> # include <sys/socket.h> # include <sys/errno.h> # include <netinet/in.h> # include <netdb.h> int sock, i, sock2; char *ptr; char buf[1024]; extern int errno; cleanup () { shutdown(sock, 2); shutdown(sock2, 2); printf ("reader : exiting\n"); exit(0); } main (argc, argv) char **argv; { struct sockaddr_in sa; struct hostent *host; FILE *in, *out; host = (struct hostent *) gethostbyname("localhost"); bzero (&sa, sizeof(struct sockaddr_in)); sa.sin_family = AF_INET; bcopy (host->h_addr, &sa.sin_addr, host->h_length); sa.sin_port = 7000; sock = socket (AF_INET, SOCK_STREAM, 0); connect (sock, &sa, sizeof(struct sockaddr_in)); if (errno) perror ("Reader Error :"); for (i = 0; i< 20; ++i) signal (i, cleanup); sock2 = dup(sock); in = fdopen(sock, "r"); out = fdopen (sock2, "w"); for (i=0; i < 3 ;i++){ # ifdef SCANF fscanf (in, "%s", buf); # else read (sock, buf, 12); # endif fprintf (stderr,"reader reads :%s\n", buf); } sprintf (buf, "Hi there, this is the reader\n"); # ifdef PRINTF fprintf(out, "%s\n", buf); # else write (sock2, buf, strlen(buf)+1); # endif fprintf (stderr, "reader : done writing %d chars\n", strlen(buf) + 1); cleanup(); }
wen-king@cit-vax.Caltech.Edu (King Su) (02/14/89)
In article <7937@netnews.upenn.edu> arup@grad1.cis.upenn.edu.UUCP (Arup Mukherjee) writes: > >To all net.wizards [again...] : First of all, you should do a 'fflush' on the FILE after you wrote to it. Since a socket file is not a character speical device, the FILE writing functions such as fprintf will cause characters to be held in an internal buffer until a buffering limit is reached or until you do a fflush. Secondly, you do not need two sockets, you just need two FILEs. You can apply fdopen on the same file twice. You don't need to dup it either. For example: in = fdopen(soc,"r"); out = fdopen(soc,"w"); Your observation, that the suggestions you got by E-mail doesn't work, probably is due to that fact that you did not use fflush. -- /*------------------------------------------------------------------------*\ | Wen-King Su wen-king@vlsi.caltech.edu Caltech Corp of Cosmic Engineers | \*------------------------------------------------------------------------*/
chris@mimsy.UUCP (Chris Torek) (02/17/89)
In article <9556@cit-vax.Caltech.Edu> wen-king@cit-vax.Caltech.Edu (King Su) writes: >in = fdopen(soc,"r"); >out = fdopen(soc,"w"); If you use this technique, be aware that fclose(in) also closes out's file descriptor, without giving it a chance to flush any pending data. Likewise, fclose(out) closes in's fd. There is also no guarantee that stdio will not get upset if fclose's implied close() fails. This might, for instance, lead to running out of FILE structures. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
smb@ulysses.homer.nj.att.com (Steven M. Bellovin) (02/19/89)
In article <9556@cit-vax.Caltech.Edu>, wen-king@cit-vax.Caltech.Edu (King Su) writes: } Secondly, you do not need two sockets, you just need two FILEs. You can } apply fdopen on the same file twice. You don't need to dup it either. } For example: } } in = fdopen(soc,"r"); } out = fdopen(soc,"w"); That is not correct for System V; you do indeed need to do the dup(). Please note that I'm speaking empirically... (i.e., it broke on me the other way.)