Date: Sun, 12 May 1996 16:15:33 +0200 From: "Christoph P. Kukulies" <kuku@gilberto.physik.rwth-aachen.de> To: freebsd-questions@freefall.FreeBSD.org Subject: tcp printing problem Message-ID: <199605121415.QAA19502@gilberto.physik.rwth-aachen.de>
next in thread | raw e-mail | index | archive | help
I'm having a weird printer problem. A Declaser 3500 is on the network and I tried to establish TCP/IP printing to that printer. On advice of Garett Wollman I'm using ttcp (comp.unix.sources) /etc/printcap: # @(#)printcap 5.3 (Berkeley) 6/30/90 # lp0|lp||rlp|lw|ps|postscript|PostScript|lp1|lw1|postscript1|PostScript1:\ :lp=/dev/null:\ :mx#0:\ :if=/usr/local/bin/infilter:\ :of=/usr/local/bin/printe:\ :sd=/var/spool/printe: /usr/local/bin/printe: #!/bin/sh /usr/local/bin/ttcp -D -t -p 10001 10.0.0.64 2>/var/log/lpd-errs Using the command cat /etc/passwd | /usr/local/bin/infilter | /usr/local/bin/printe works fine and the file gets printed to the network printer. But doing this under lpd control I get May 12 15:57:52 isdn-kukulies lpd[27554]: lp: output filter died (retcode=2 termsig=0) I can't find a core dump though. the spool files are in /var/spool/printe and lpq reports ready and printing. I include the source and man page of ttcp also. --Chris Christoph P. U. Kukulies kuku@gil.physik.rwth-aachen.de ----- ttcp.c ----- /* * T T C P . C * * Test TCP connection. Makes a connection on port 5001 * and transfers fabricated buffers or data copied from stdin. * * Usable on 4.2, 4.3, and 4.1a systems by defining one of * BSD42 BSD43 (BSD41a) * Machines using System V with BSD sockets should define SYSV. * * Modified for operation under 4.2BSD, 18 Dec 84 * T.C. Slattery, USNA * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85. * Modified in 1989 at Silicon Graphics, Inc. * catch SIGPIPE to be able to print stats when receiver has died * for tcp, don't look for sentinel during reads to allow small transfers * increased default buffer size to 8K, nbuf to 2K to transfer 16MB * moved default port to 5001, beyond IPPORT_USERRESERVED * make sinkmode default because it is more popular, * -s now means don't sink/source * count number of read/write system calls to see effects of * blocking from full socket buffers * for tcp, -D option turns off buffered writes (sets TCP_NODELAY sockopt) * buffer alignment options, -A and -O * print stats in a format that's a bit easier to use with grep & awk * for SYSV, mimic BSD routines to use most of the existing timing code * Modified by Steve Miller of the University of Maryland, College Park * -b sets the socket buffer size (SO_SNDBUF/SO_RCVBUF) * Modified Sept. 1989 at Silicon Graphics, Inc. * restored -s sense at request of tcs@brl * Modified Oct. 1991 at Silicon Graphics, Inc. * use getopt(3) for option processing, add -f and -T options. * SGI IRIX 3.3 and 4.0 releases don't need #define SYSV. * * Distribution Status - * Public Domain. Distribution Unlimited. */ #ifndef lint static char RCSid[] = "ttcp.c $Revision: 1.12 $"; #endif #define BSD43 /* #define BSD42 */ /* #define BSD41a */ /* #define SYSV */ /* required on SGI IRIX releases before 3.3 */ #include <stdio.h> #include <signal.h> #include <ctype.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <netdb.h> #include <sys/time.h> /* struct timeval */ #if defined(SYSV) #include <sys/times.h> #include <sys/param.h> struct rusage { struct timeval ru_utime, ru_stime; }; #define RUSAGE_SELF 0 #else #include <sys/resource.h> #endif struct sockaddr_in sinme; struct sockaddr_in sinhim; struct sockaddr_in frominet; int domain, fromlen; int fd; /* fd of network socket */ int buflen = 8 * 1024; /* length of buffer */ char *buf; /* ptr to dynamic buffer */ int nbuf = 2 * 1024; /* number of buffers to send in sinkmode */ int bufoffset = 0; /* align buffer to this */ int bufalign = 16*1024; /* modulo this */ int udp = 0; /* 0 = tcp, !0 = udp */ int options = 0; /* socket options */ int one = 1; /* for 4.3 BSD style setsockopt() */ short port = 5001; /* TCP port number */ char *host; /* ptr to name of host */ int trans; /* 0=receive, !0=transmit mode */ int sinkmode = 0; /* 0=normal I/O, !0=sink/source mode */ int verbose = 0; /* 0=print basic info, 1=print cpu rate, proc * resource usage. */ int nodelay = 0; /* set TCP_NODELAY socket option */ int b_flag = 0; /* use mread() */ int sockbufsize = 0; /* socket buffer size to use */ char fmt = 'K'; /* output format: k = kilobits, K = kilobytes, * m = megabits, M = megabytes, * g = gigabits, G = gigabytes */ int touchdata = 0; /* access data after reading */ struct hostent *addr; extern int errno; extern int optind; extern char *optarg; char Usage[] = "\ Usage: ttcp -t [-options] host [ < in ]\n\ ttcp -r [-options > out]\n\ Common options:\n\ -l ## length of bufs read from or written to network (default 8192)\n\ -u use UDP instead of TCP\n\ -p ## port number to send to or listen at (default 5001)\n\ -s -t: source a pattern to network\n\ -r: sink (discard) all data from network\n\ -A align the start of buffers to this modulus (default 16384)\n\ -O start buffers at this offset from the modulus (default 0)\n\ -v verbose: print more statistics\n\ -d set SO_DEBUG socket option\n\ -b ## set socket buffer size (if supported)\n\ -f X format for rate: k,K = kilo{bit,byte}; m,M = mega; g,G = giga\n\ Options specific to -t:\n\ -n## number of source bufs written to network (default 2048)\n\ -D don't buffer TCP writes (sets TCP_NODELAY socket option)\n\ Options specific to -r:\n\ -B for -s, only output full blocks as specified by -l (for TAR)\n\ -T \"touch\": access each byte as it's read\n\ "; char stats[128]; double nbytes; /* bytes on net */ unsigned long numCalls; /* # of I/O system calls */ double cput, realt; /* user, real time (seconds) */ void err(); void mes(); int pattern(); void prep_timer(); double read_timer(); int Nread(); int Nwrite(); void delay(); int mread(); char *outfmt(); void sigpipe() { } main(argc,argv) int argc; char **argv; { unsigned long addr_tmp; int c; if (argc < 2) goto usage; while ((c = getopt(argc, argv, "drstuvBDTb:f:l:n:p:A:O:")) != -1) { switch (c) { case 'B': b_flag = 1; break; case 't': trans = 1; break; case 'r': trans = 0; break; case 'd': options |= SO_DEBUG; break; case 'D': #ifdef TCP_NODELAY nodelay = 1; #else fprintf(stderr, "ttcp: -D option ignored: TCP_NODELAY socket option not supported\n"); #endif break; case 'n': nbuf = atoi(optarg); break; case 'l': buflen = atoi(optarg); break; case 's': sinkmode = !sinkmode; break; case 'p': port = atoi(optarg); break; case 'u': udp = 1; break; case 'v': verbose = 1; break; case 'A': bufalign = atoi(optarg); break; case 'O': bufoffset = atoi(optarg); break; case 'b': #if defined(SO_SNDBUF) || defined(SO_RCVBUF) sockbufsize = atoi(optarg); #else fprintf(stderr, "ttcp: -b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported\n"); #endif break; case 'f': fmt = *optarg; break; case 'T': touchdata = 1; break; default: goto usage; } } if(trans) { /* xmitr */ if (optind == argc) goto usage; bzero((char *)&sinhim, sizeof(sinhim)); host = argv[optind]; if (atoi(host) > 0 ) { /* Numeric */ sinhim.sin_family = AF_INET; #if defined(cray) addr_tmp = inet_addr(host); sinhim.sin_addr = addr_tmp; #else sinhim.sin_addr.s_addr = inet_addr(host); #endif } else { if ((addr=gethostbyname(host)) == NULL) err("bad hostname"); sinhim.sin_family = addr->h_addrtype; bcopy(addr->h_addr,(char*)&addr_tmp, addr->h_length); #if defined(cray) sinhim.sin_addr = addr_tmp; #else sinhim.sin_addr.s_addr = addr_tmp; #endif /* cray */ } sinhim.sin_port = htons(port); sinme.sin_port = 0; /* free choice */ } else { /* rcvr */ sinme.sin_port = htons(port); } if (udp && buflen < 5) { buflen = 5; /* send more than the sentinel size */ } if ( (buf = (char *)malloc(buflen+bufalign)) == (char *)NULL) err("malloc"); if (bufalign != 0) buf +=(bufalign - ((int)buf % bufalign) + bufoffset) % bufalign; if (trans) { fprintf(stdout, "ttcp-t: buflen=%d, nbuf=%d, align=%d/%d, port=%d", buflen, nbuf, bufalign, bufoffset, port); if (sockbufsize) fprintf(stdout, ", sockbufsize=%d", sockbufsize); fprintf(stdout, " %s -> %s\n", udp?"udp":"tcp", host); } else { fprintf(stdout, "ttcp-r: buflen=%d, nbuf=%d, align=%d/%d, port=%d", buflen, nbuf, bufalign, bufoffset, port); if (sockbufsize) fprintf(stdout, ", sockbufsize=%d", sockbufsize); fprintf(stdout, " %s\n", udp?"udp":"tcp"); } if ((fd = socket(AF_INET, udp?SOCK_DGRAM:SOCK_STREAM, 0)) < 0) err("socket"); mes("socket"); if (bind(fd, &sinme, sizeof(sinme)) < 0) err("bind"); #if defined(SO_SNDBUF) || defined(SO_RCVBUF) if (sockbufsize) { if (trans) { if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sockbufsize, sizeof sockbufsize) < 0) err("setsockopt: sndbuf"); mes("sndbuf"); } else { if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sockbufsize, sizeof sockbufsize) < 0) err("setsockopt: rcvbuf"); mes("rcvbuf"); } } #endif if (!udp) { signal(SIGPIPE, sigpipe); if (trans) { /* We are the client if transmitting */ if (options) { #if defined(BSD42) if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0) #else /* BSD43 */ if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0) #endif err("setsockopt"); } #ifdef TCP_NODELAY if (nodelay) { struct protoent *p; p = getprotobyname("tcp"); if( p && setsockopt(fd, p->p_proto, TCP_NODELAY, &one, sizeof(one)) < 0) err("setsockopt: nodelay"); mes("nodelay"); } #endif if(connect(fd, &sinhim, sizeof(sinhim) ) < 0) err("connect"); mes("connect"); } else { /* otherwise, we are the server and * should listen for the connections */ #if defined(ultrix) || defined(sgi) listen(fd,1); /* workaround for alleged u4.2 bug */ #else listen(fd,0); /* allow a queue of 0 */ #endif if(options) { #if defined(BSD42) if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0) #else /* BSD43 */ if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0) #endif err("setsockopt"); } fromlen = sizeof(frominet); domain = AF_INET; if((fd=accept(fd, &frominet, &fromlen) ) < 0) err("accept"); { struct sockaddr_in peer; int peerlen = sizeof(peer); if (getpeername(fd, (struct sockaddr_in *) &peer, &peerlen) < 0) { err("getpeername"); } fprintf(stderr,"ttcp-r: accept from %s\n", inet_ntoa(peer.sin_addr)); } } } prep_timer(); errno = 0; if (sinkmode) { register int cnt; if (trans) { pattern( buf, buflen ); if(udp) (void)Nwrite( fd, buf, 4 ); /* rcvr start */ while (nbuf-- && Nwrite(fd,buf,buflen) == buflen) nbytes += buflen; if(udp) (void)Nwrite( fd, buf, 4 ); /* rcvr end */ } else { if (udp) { while ((cnt=Nread(fd,buf,buflen)) > 0) { static int going = 0; if( cnt <= 4 ) { if( going ) break; /* "EOF" */ going = 1; prep_timer(); } else { nbytes += cnt; } } } else { while ((cnt=Nread(fd,buf,buflen)) > 0) { nbytes += cnt; } } } } else { register int cnt; if (trans) { while((cnt=read(0,buf,buflen)) > 0 && Nwrite(fd,buf,cnt) == cnt) nbytes += cnt; } else { while((cnt=Nread(fd,buf,buflen)) > 0 && write(1,buf,cnt) == cnt) nbytes += cnt; } } if(errno) err("IO"); (void)read_timer(stats,sizeof(stats)); if(udp&&trans) { (void)Nwrite( fd, buf, 4 ); /* rcvr end */ (void)Nwrite( fd, buf, 4 ); /* rcvr end */ (void)Nwrite( fd, buf, 4 ); /* rcvr end */ (void)Nwrite( fd, buf, 4 ); /* rcvr end */ } if( cput <= 0.0 ) cput = 0.001; if( realt <= 0.0 ) realt = 0.001; fprintf(stdout, "ttcp%s: %.0f bytes in %.2f real seconds = %s/sec +++\n", trans?"-t":"-r", nbytes, realt, outfmt(nbytes/realt)); if (verbose) { fprintf(stdout, "ttcp%s: %.0f bytes in %.2f CPU seconds = %s/cpu sec\n", trans?"-t":"-r", nbytes, cput, outfmt(nbytes/cput)); } fprintf(stdout, "ttcp%s: %d I/O calls, msec/call = %.2f, calls/sec = %.2f\n", trans?"-t":"-r", numCalls, 1024.0 * realt/((double)numCalls), ((double)numCalls)/realt); fprintf(stdout,"ttcp%s: %s\n", trans?"-t":"-r", stats); if (verbose) { fprintf(stdout, "ttcp%s: buffer address %#x\n", trans?"-t":"-r", buf); } exit(0); usage: fprintf(stderr,Usage); exit(1); } void err(s) char *s; { fprintf(stderr,"ttcp%s: ", trans?"-t":"-r"); perror(s); fprintf(stderr,"errno=%d\n",errno); exit(1); } void mes(s) char *s; { fprintf(stderr,"ttcp%s: %s\n", trans?"-t":"-r", s); } pattern( cp, cnt ) register char *cp; register int cnt; { register char c; c = 0; while( cnt-- > 0 ) { while( !isprint((c&0x7F)) ) c++; *cp++ = (c++&0x7F); } } char * outfmt(b) double b; { static char obuf[50]; switch (fmt) { case 'G': sprintf(obuf, "%.2f GB", b / 1024.0 / 1024.0 / 1024.0); break; default: case 'K': sprintf(obuf, "%.2f KB", b / 1024.0); break; case 'M': sprintf(obuf, "%.2f MB", b / 1024.0 / 1024.0); break; case 'g': sprintf(obuf, "%.2f Gbit", b * 8.0 / 1024.0 / 1024.0 / 1024.0); break; case 'k': sprintf(obuf, "%.2f Kbit", b * 8.0 / 1024.0); break; case 'm': sprintf(obuf, "%.2f Mbit", b * 8.0 / 1024.0 / 1024.0); break; } return obuf; } static struct timeval time0; /* Time at which timing started */ static struct rusage ru0; /* Resource utilization at the start */ static void prusage(); static void tvadd(); static void tvsub(); static void psecs(); #if defined(SYSV) /*ARGSUSED*/ static getrusage(ignored, ru) int ignored; register struct rusage *ru; { struct tms buf; times(&buf); /* Assumption: HZ <= 2147 (LONG_MAX/1000000) */ ru->ru_stime.tv_sec = buf.tms_stime / HZ; ru->ru_stime.tv_usec = ((buf.tms_stime % HZ) * 1000000) / HZ; ru->ru_utime.tv_sec = buf.tms_utime / HZ; ru->ru_utime.tv_usec = ((buf.tms_utime % HZ) * 1000000) / HZ; } /*ARGSUSED*/ static gettimeofday(tp, zp) struct timeval *tp; struct timezone *zp; { tp->tv_sec = time(0); tp->tv_usec = 0; } #endif /* SYSV */ /* * P R E P _ T I M E R */ void prep_timer() { gettimeofday(&time0, (struct timezone *)0); getrusage(RUSAGE_SELF, &ru0); } /* * R E A D _ T I M E R * */ double read_timer(str,len) char *str; { struct timeval timedol; struct rusage ru1; struct timeval td; struct timeval tend, tstart; char line[132]; getrusage(RUSAGE_SELF, &ru1); gettimeofday(&timedol, (struct timezone *)0); prusage(&ru0, &ru1, &timedol, &time0, line); (void)strncpy( str, line, len ); /* Get real time */ tvsub( &td, &timedol, &time0 ); realt = td.tv_sec + ((double)td.tv_usec) / 1000000; /* Get CPU time (user+sys) */ tvadd( &tend, &ru1.ru_utime, &ru1.ru_stime ); tvadd( &tstart, &ru0.ru_utime, &ru0.ru_stime ); tvsub( &td, &tend, &tstart ); cput = td.tv_sec + ((double)td.tv_usec) / 1000000; if( cput < 0.00001 ) cput = 0.00001; return( cput ); } static void prusage(r0, r1, e, b, outp) register struct rusage *r0, *r1; struct timeval *e, *b; char *outp; { struct timeval tdiff; register time_t t; register char *cp; register int i; int ms; t = (r1->ru_utime.tv_sec-r0->ru_utime.tv_sec)*100+ (r1->ru_utime.tv_usec-r0->ru_utime.tv_usec)/10000+ (r1->ru_stime.tv_sec-r0->ru_stime.tv_sec)*100+ (r1->ru_stime.tv_usec-r0->ru_stime.tv_usec)/10000; ms = (e->tv_sec-b->tv_sec)*100 + (e->tv_usec-b->tv_usec)/10000; #define END(x) {while(*x) x++;} #if defined(SYSV) cp = "%Uuser %Ssys %Ereal %P"; #else #if defined(sgi) /* IRIX 3.3 will show 0 for %M,%F,%R,%C */ cp = "%Uuser %Ssys %Ereal %P %Mmaxrss %F+%Rpf %Ccsw"; #else cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw"; #endif #endif for (; *cp; cp++) { if (*cp != '%') *outp++ = *cp; else if (cp[1]) switch(*++cp) { case 'U': tvsub(&tdiff, &r1->ru_utime, &r0->ru_utime); sprintf(outp,"%d.%01d", tdiff.tv_sec, tdiff.tv_usec/100000); END(outp); break; case 'S': tvsub(&tdiff, &r1->ru_stime, &r0->ru_stime); sprintf(outp,"%d.%01d", tdiff.tv_sec, tdiff.tv_usec/100000); END(outp); break; case 'E': psecs(ms / 100, outp); END(outp); break; case 'P': sprintf(outp,"%d%%", (int) (t*100 / ((ms ? ms : 1)))); END(outp); break; #if !defined(SYSV) case 'W': i = r1->ru_nswap - r0->ru_nswap; sprintf(outp,"%d", i); END(outp); break; case 'X': sprintf(outp,"%d", t == 0 ? 0 : (r1->ru_ixrss-r0->ru_ixrss)/t); END(outp); break; case 'D': sprintf(outp,"%d", t == 0 ? 0 : (r1->ru_idrss+r1->ru_isrss-(r0->ru_idrss+r0->ru_isrss))/t); END(outp); break; case 'K': sprintf(outp,"%d", t == 0 ? 0 : ((r1->ru_ixrss+r1->ru_isrss+r1->ru_idrss) - (r0->ru_ixrss+r0->ru_idrss+r0->ru_isrss))/t); END(outp); break; case 'M': sprintf(outp,"%d", r1->ru_maxrss/2); END(outp); break; case 'F': sprintf(outp,"%d", r1->ru_majflt-r0->ru_majflt); END(outp); break; case 'R': sprintf(outp,"%d", r1->ru_minflt-r0->ru_minflt); END(outp); break; case 'I': sprintf(outp,"%d", r1->ru_inblock-r0->ru_inblock); END(outp); break; case 'O': sprintf(outp,"%d", r1->ru_oublock-r0->ru_oublock); END(outp); break; case 'C': sprintf(outp,"%d+%d", r1->ru_nvcsw-r0->ru_nvcsw, r1->ru_nivcsw-r0->ru_nivcsw ); END(outp); break; #endif /* !SYSV */ } } *outp = '\0'; } static void tvadd(tsum, t0, t1) struct timeval *tsum, *t0, *t1; { tsum->tv_sec = t0->tv_sec + t1->tv_sec; tsum->tv_usec = t0->tv_usec + t1->tv_usec; if (tsum->tv_usec > 1000000) tsum->tv_sec++, tsum->tv_usec -= 1000000; } static void tvsub(tdiff, t1, t0) struct timeval *tdiff, *t1, *t0; { tdiff->tv_sec = t1->tv_sec - t0->tv_sec; tdiff->tv_usec = t1->tv_usec - t0->tv_usec; if (tdiff->tv_usec < 0) tdiff->tv_sec--, tdiff->tv_usec += 1000000; } static void psecs(l,cp) long l; register char *cp; { register int i; i = l / 3600; if (i) { sprintf(cp,"%d:", i); END(cp); i = l % 3600; sprintf(cp,"%d%d", (i/60) / 10, (i/60) % 10); END(cp); } else { i = l; sprintf(cp,"%d", i / 60); END(cp); } i %= 60; *cp++ = ':'; sprintf(cp,"%d%d", i / 10, i % 10); } /* * N R E A D */ Nread( fd, buf, count ) int fd; void *buf; int count; { struct sockaddr_in from; int len = sizeof(from); register int cnt; if( udp ) { cnt = recvfrom( fd, buf, count, 0, &from, &len ); numCalls++; } else { if( b_flag ) cnt = mread( fd, buf, count ); /* fill buf */ else { cnt = read( fd, buf, count ); numCalls++; } if (touchdata && cnt > 0) { register int c = cnt, sum; register char *b = buf; while (c--) sum += *b++; } } return(cnt); } /* * N W R I T E */ Nwrite( fd, buf, count ) int fd; void *buf; int count; { register int cnt; if( udp ) { again: cnt = sendto( fd, buf, count, 0, &sinhim, sizeof(sinhim) ); numCalls++; if( cnt<0 && errno == ENOBUFS ) { delay(18000); errno = 0; goto again; } } else { cnt = write( fd, buf, count ); numCalls++; } return(cnt); } void delay(us) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = us; (void)select( 1, (char *)0, (char *)0, (char *)0, &tv ); } /* * M R E A D * * This function performs the function of a read(II) but will * call read(II) multiple times in order to get the requested * number of characters. This can be necessary because * network connections don't deliver data with the same * grouping as it is written with. Written by Robert S. Miles, BRL. */ int mread(fd, bufp, n) int fd; register char *bufp; unsigned n; { register unsigned count = 0; register int nread; do { nread = read(fd, bufp, n-count); numCalls++; if(nread < 0) { perror("ttcp_mread"); return(-1); } if(nread == 0) return((int)count); count += (unsigned)nread; bufp += nread; } while(count < n); return((int)count); } ----- ttcp.1 ---- '\"macro stdmacro .TH TTCP 1 local .SH NAME ttcp \- test TCP and UDP performance .SH SYNOPSIS .B ttcp \-t .RB [ \-u ] .RB [ \-s ] .RB [ \-p\0 \fIport\fP ] .RB [ \-l\0 \fIbuflen\fP ] .RB [ \-b\0 \fIsize\fP ] .RB [ \-n\0 \fInumbufs\fP ] .RB [ \-A\0 \fIalign\fP ] .RB [ \-O\0 \fIoffset\fP ] .RB [ \-f\0 \fIformat\fP ] .RB [ \-D ] .RB [ \-v] .RB host .RB [ < in ] .br .B ttcp \-r .RB [ \-u ] .RB [ \-s ] .RB [ \-p\0 \fIport\fP ] .RB [ \-l\0 \fIbuflen\fP ] .RB [ \-b\0 \fIsize\fP ] .RB [ \-A\0 \fIalign\fP ] .RB [ \-O\0 \fIoffset\fP ] .RB [ \-f\0 \fIformat\fP ] .RB [ \-B ] .RB [ \-T ] .RB [ \-v ] .RB [ > out ] .SH DESCRIPTION .I Ttcp times the transmission and reception of data between two systems using the UDP or TCP protocols. It differs from common ``blast'' tests, which tend to measure the remote .I inetd as much as the network performance, and which usually do not allow measurements at the remote end of a UDP transmission. .PP For testing, the transmitter should be started with \f3\-t\f1 and \f3\-s\f1 after the receiver has been started with \f3\-r\f1 and \f3\-s\f1. Tests lasting at least tens of seconds should be used to obtain accurate measurements. Graphical presentations of throughput versus buffer size for buffers ranging from tens of bytes to several ``pages'' can illuminate bottlenecks. .PP .I Ttcp can also be used as a ``network pipe'' for moving directory hierarchies between systems when routing problems exist or when the use of other mechanisms is undesirable. For example, on the destination machine, use: .Ex ttcp \-r \-B | tar xvpf \- .Ee .PP and on the source machine: .Ex tar cf \- directory | ttcp \-t dest_machine .Ee .PP Additional intermediate machines can be included by: .Ex ttcp \-r | ttcp \-t next_machine .Ee .SH OPTIONS .TP 10 \-t Transmit mode. .TP 10 \-r Receive mode. .TP 10 \-u Use UDP instead of TCP. .TP 10 \-s If transmitting, source a data pattern to network; if receiving, sink (discard) the data. Without the \f3\-s\f1 option, the default is to transmit data from .I stdin or print the received data to .IR stdout . .TP 10 \-l \fIlength\fP Length of buffers in bytes (default 8192). For UDP, this value is the number of data bytes in each packet. The system limits the maximum UDP packet length. This limit can be changed with the \f3\-b\f1 option. .TP 10 \-b \fIsize\fP Set size of socket buffer. The default varies from system to system. This parameter affects the maximum UDP packet length. It may not be possible to set this parameter on some systems (for example, 4.2BSD). .TP 10 \-n \fInumbufs\fP Number of source buffers transmitted (default 2048). .TP 10 \-p \fIport\fP Port number to send to or listen on (default 2000). On some systems, this port may be allocated to another network daemon. .TP 10 \-D If transmitting using TCP, do not buffer data when sending (sets the TCP_NODELAY socket option). It may not be possible to set this parameter on some systems (for example, 4.2BSD). .TP 10 \-B When receiving data, output only full blocks, using the block size specified by \f3\-l\f1. This option is useful for programs, such as \f2tar\f1(1), that require complete blocks. .TP 10 \-A \fIalign\fP Align the start of buffers to this modulus (default 16384). .TP 10 \-O \fIoffset\fP Align the start of buffers to this offset (default 0). For example, ``\-A8192 \-O1'' causes buffers to start at the second byte of an 8192-byte page. .TP 10 \-f \fIformat\fP Specify, using one of the following characters, the format of the throughput rates as kilobits/sec ('k'), kilobytes/sec ('K'), megabits/sec ('m'), megabytes/sec ('M'), gigabits/sec ('g'), or gigabytes/sec ('G'). The default is 'K'. .TP 10 \-T ``Touch'' the data as they are read in order to measure cache effects. .TP 10 \-v Verbose: print more statistics. .TP 10 \-d Debug: set the SO_DEBUG socket option. .SH SEE ALSO ping(1M), traceroute(1M), netsnoop(1M)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199605121415.QAA19502>