Date: Fri, 17 Mar 1995 12:44:38 -0500 From: der Mouse <mouse@Collatz.McRCIM.McGill.EDU> To: mycroft@ai.mit.edu Cc: hackers@FreeBSD.org, peter@bonkers.taronga.com, tech-net@NetBSD.ORG, terry@cs.weber.edu Subject: Re: Batch Telnet (Re: diskless and 3Com 509) Message-ID: <199503171744.MAA16759@Collatz.McRCIM.McGill.EDU>
next in thread | raw e-mail | index | archive | help
> The problem is that the client is closing the connection. If the > telnet client's stdin gets an EOF, one might expect it should at most > close the write side of the TCP connection (i.e. use the shutdown(2) > system call). Right, that's exactly what I'd hope it would do. I don't think I've ever met a telnet client that did, though. > With a more reasonable protocol, you'd expect the half-close to be > propagated to the server, and the server would notice it and shut > down if appropriate. However, TCP doesn't have a half-close > mechanism. It sure did last time I read the RFC; either end can send a FIN packet and continue to receive data in the other direction "forever", until the other end sends a FIN or until the local TCP client insists on closing down the read half of the connection. Indeed, this is how it works in practice. In case you still doubt, here are a pair of programs. sample-s.c is the server, sample-c.c is the client. Run sample-s, then (on the same machine) run sample-c. Type stuff at sample-c and it will be sent to sample-s; anything received from sample-s will be printed. Type your EOF character to sample-c and it will shutdown half the connection and stop listening to stdin, but will continue to listen to the read half of the connection. When it sees the s->c half of the connection drop, it exits. sample-s reads stuff from sample-c and echoes it back, until it gets EOF on the c->s half of the connection. At this point it sleeps for five seconds, prints the sum of all the bytes received, sleeps for five more seconds, shuts down the s->c half of the connection, sleeps for another five seconds, and exits. sample-s also prints to its own stdout a trace of the actions it's taking. These compile and work under gcc 2.6.3 on our SunOS 4.1.2 Suns, and under cc on NetBSD/sparc 1.0 (not tested under -current). der Mouse mouse@collatz.mcrcim.mcgill.edu #! /bin/sh # # Shar: Shell Archiver # # This archive created Fri Mar 17 12:42:23 1995 # Run this through sh to create: # sample-c.c # sample-s.c echo x - sample-c.c \(1268 characters\) sed 's/^X//' > sample-c.c << \EOF X#include <stdio.h> X#include <errno.h> X#include <strings.h> X#include <sys/types.h> X#include <sys/socket.h> X#include <netinet/in.h> X#include <arpa/inet.h> X X#define PORT 9876 X Xvoid main(void); Xvoid main(void) X{ X int s; X struct sockaddr_in sin; X int n; X int sending; X fd_set fds; X char buf[256]; X X s = socket(AF_INET,SOCK_STREAM,0); X if (s < 0) X { perror("socket"); X exit(1); X } X bzero(&sin,sizeof(sin)); X sin.sin_family = AF_INET; X sin.sin_addr.s_addr = inet_addr("127.0.0.1"); X sin.sin_port = htons(PORT); X if (connect(s,(struct sockaddr *)&sin,sizeof(sin)) < 0) X { perror("connect"); X exit(1); X } X sending = 1; X while (1) X { FD_ZERO(&fds); X if (sending) FD_SET(0,&fds); X FD_SET(s,&fds); X n = select(FD_SETSIZE,&fds,0,0,0); X if (n < 0) X { if (errno == EINTR) continue; X perror("select"); X exit(1); X } X if (FD_ISSET(s,&fds)) X { n = read(s,&buf[0],sizeof(buf)); X if (n < 0) X { perror("net read"); X exit(1); X } X if (n == 0) exit(0); X write(1,&buf[0],n); X } X if (sending && FD_ISSET(0,&fds)) X { n = read(0,&buf[0],sizeof(buf)); X if (n < 0) X { perror("stdin read"); X exit(1); X } X if (n == 0) X { shutdown(s,1); X sending = 0; X } X else X { write(s,&buf[0],n); X } X } X } X} EOF if test 1268 -ne "`wc -c sample-c.c`" then echo shar: error transmitting sample-c.c \(should have been 1268 characters\) fi echo x - sample-s.c \(1316 characters\) sed 's/^X//' > sample-s.c << \EOF X#include <stdio.h> X#include <strings.h> X#include <sys/types.h> X#include <sys/socket.h> X#include <netinet/in.h> X X#define PORT 9876 X Xvoid main(void); Xvoid main(void) X{ X int acc; X int s; X struct sockaddr_in sin; X int sinlen; X char buf[256]; X int n; X int i; X unsigned int sum; X X acc = socket(AF_INET,SOCK_STREAM,0); X if (acc < 0) X { perror("socket"); X exit(1); X } X bzero(&sin,sizeof(sin)); X sin.sin_family = AF_INET; X sin.sin_addr.s_addr = INADDR_ANY; X sin.sin_port = htons(PORT); X if (bind(acc,(struct sockaddr *)&sin,sizeof(sin)) < 0) X { perror("bind"); X exit(1); X } X listen(acc,1); X sinlen = sizeof(sin); X s = accept(acc,(struct sockaddr *)&sin,&sinlen); X if (s < 0) X { perror("accept"); X exit(1); X } X close(acc); X sum = 0; X while (1) X { n = read(s,&buf[0],sizeof(buf)); X if (n < 0) X { perror("read"); X exit(1); X } X if (n == 0) break; X write(s,&buf[0],n); X for (i=0;i<n;i++) sum += (unsigned char) buf[i]; X printf("echoed %d, sum now %u\n",n,sum); X } X printf("got read EOF, sleeping\n"); X sleep(5); X printf("sending sum=%u\n",sum); X sprintf(&buf[0],"%u\n",sum); X write(s,&buf[0],strlen(&buf[0])); X printf("sleeping again\n"); X sleep(5); X printf("shutting down s->c connection\n"); X shutdown(s,1); X printf("sleeping again\n"); X sleep(5); X printf("exiting\n"); X exit(0); X} EOF if test 1316 -ne "`wc -c sample-s.c`" then echo shar: error transmitting sample-s.c \(should have been 1316 characters\) fi exit 0 # end of shell archive
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199503171744.MAA16759>