---------------------------------------------------------------------------- This file contains source code for examples to accompany the spring 1997 DECUS seminar "S312 - TCP/IP Programming" Postscript of the accompanying slides is contained in this same directory. Filename: tcp_ip_programming.ps. Table of Contents (of this file): 1. Stream (TCP) discard client example (from talk) 2. Stream (TCP) discard server example (from talk) 3. For VMS people - UCX Master server programming memo (not in talk) Note that the discard server example is set up to run at port 64001, so if you want to use the client to send data to the server make sure to specify port 64001 when you invoke the client (see client "usage") Edit this file, cutting out the TCP_DISCARD_CLIENT.C and TCP_DISCARD_SERVER.C Compile and link them according to the instructions in the comments at the beginning of each program. If you find any bugs in these examples (or want to share neat enhancements) send them to "wwagner@process.com" Enjoy! ----------- TCP_DISCARD_CLIENT.C starts here -------------------------------- /* ** DISCARD Protocol Client (RFC-863) ** ** This client has been tested on SunOS UNIX 4.1, ** VAX VMS 5.5-2 and AXP VMS 6.1. VMS systems were ** running TCPware 4.1-3. ** ** Build and run on UNIX via: ** % cc tcp_discard_client.c ** % a.out [port] ** ** Build on VAX VMS via: ** $ CC TCP_DISCARD_CLIENT.C ** $ LINK TCP_DISCARD_CLIENT,TCPWARE:UCX$IPC/LIB,SYS$INPUT/OPTIONS ** SYS$SHARE:VAXCRTL/SHARE ** ** Build on AXP VMS via: ** $ CC/STANDARD=VAXC TCP_DISCARD_CLIENT.C ** $ LINK TCP_DISCARD_CLIENT ** ** Run on VMS via: ** $ DISCARD :== $:[DIR]TCP_DISCARD_CLIENT.EXE ** $ DISCARD [PORT] */ #ifdef VMS #include #include #include #include #include #include #include #include #include #else #include #include #include #include #include #include #include #include #include #include #endif #ifdef VMS #define bcopy(s,d,l) memcpy(d,s,l) #define bzero(d,l) memset(d,0,l) #endif main(argc, argv) int argc; char *argv[]; { int sock, pktcnt, size, i, n, bytes; int port = 9; struct hostent *he; struct servent *se; struct sockaddr_in name; struct timeb stat_etime, stat_stime, stat_time; float seconds, kbsec; char buffer[32768]; /* ** Parse the command: ** discard <#-sends> [] */ if ((argc < 4) || (argc > 5)) goto usage; if (sscanf(argv[2],"%d",&pktcnt) == 0) goto usage; if (sscanf(argv[3],"%d",&size) == 0) goto usage; if (size > sizeof(buffer)) exit(0); for (n=0;nh_addr,(char *)&name.sin_addr,he->h_length); name.sin_family = he->h_addrtype; } else { name.sin_addr.s_addr = inet_addr(argv[1]); name.sin_family = AF_INET; } if (name.sin_addr.s_addr == 0xFFFFFFFF) { printf("Unknown host name\n"); exit(0); } /* ** Parse the service (or port number) argument if ** specified. If not, use "discard" (or port 9). */ if (argc > 4) { se = getservbyname(argv[4],"tcp"); #ifdef VAX /* work-around bug in VAX C RTL */ if ((se == NULL) || (se == -1)) { #else if (se == NULL) { #endif sscanf(argv[4],"%d",&port); name.sin_port = htons(port); } else name.sin_port = se->s_port; } else { se = getservbyname("discard","tcp"); #ifdef VAX /* work-around bug in VAX C RTL */ if ((se == NULL) || (se == -1)) #else if (se == NULL) #endif name.sin_port = htons(port); else name.sin_port = se->s_port; } /* ** 1. Create a stream (TCP) socket. */ sock = socket(AF_INET,SOCK_STREAM,0); if (sock <= 0) { perror("socket"); exit(0); } /* ** 2. Open the connection to the server. */ if (connect(sock,&name,sizeof(name)) < 0) { perror("connect"); exit(0); } printf("Connected to %s,%d. Sending data ...\n", argv[1],ntohs(name.sin_port)); bytes = 0; ftime(&stat_stime); /* ** 3. Send the data until we've either sent everything ** asked or some error is returned. */ for (i=0; i #include #include #include #include #include #include #include #include #else #include #include #include #include #include #include #include #include #include #include #endif #ifdef VMS #define bzero(d,l) memset(d,0,l) #endif unsigned char buffer[16384]; main() { int lsock, sock, len; struct servent *se; struct hostent *he; struct sockaddr_in local_addr, remote_addr; unsigned long bytes; struct timeb stat_etime, stat_stime, stat_time; float seconds, kbsec; /* ** 1. Create the listen socket. */ lsock = socket(AF_INET,SOCK_STREAM,0); if (lsock <= 0) { perror("socket"); exit(1); } /* ** 2. Bind the listen socket to the well-known port. */ bzero((char *)&local_addr,sizeof(local_addr)); local_addr.sin_family = AF_INET; #ifdef PROTOTYPE_PORT local_addr.sin_port = htons(PROTOTYPE_PORT); #else /* not prototype, look up the service by name */ sd = getservbyname("discard","tcp"); #ifdef VAX /* work-around bug in VAX C RTL */ if (se != NULL) || (se != -1) #else if (se != NULL) #endif /* VAX */ local_addr.sin_port = se->s_port; else local_addr.sin_port = htons(9); #endif /* PROTOTYPE_PORT */ if (bind(lsock,&local_addr,sizeof(local_addr)) < 0) { perror("bind"); exit(1); } /* ** 3. Set the socket to accept incoming connections. */ if (listen(lsock,5) < 0) { perror("listen"); exit(1); } /* ** 4. Wait for a connection. */ next_connection: len = sizeof(remote_addr); sock = accept(lsock,&remote_addr,&len); if (sock < 0) { perror("accept"); exit(1); } /* ** 5. Loop receiving data from peer until the connection ** is closed (or an error occurs). */ bytes = 0; ftime(&stat_stime); while ((len = recv(sock,buffer,sizeof(buffer),0)) > 0) bytes += len; /* ** 6. Close the connection. */ close(sock); /* ** Log the results (k-bytes/second). */ he = gethostbyaddr(remote_addr.sin_addr.s_addr,4,AF_INET); ftime(&stat_etime); stat_time.time = stat_etime.time - stat_stime.time; stat_time.millitm = stat_etime.millitm - stat_stime.millitm; seconds = ((short) stat_time.millitm)/1000.0; seconds += stat_time.time; kbsec = bytes/seconds/1024.0; printf("Received %d bytes in %.2f seconds (%.3f KB/sec) from %s,%d.\n", bytes,seconds,kbsec, he ? he->h_name : inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port)); /* ** 7. Loop to wait for another connection. */ goto next_connection; } --------------- end of TCP_DISCARD_SERVER.C --------------------------------- --------------- UCX auxiliary server (master server) memo ------------------- (For VMS people...) Q: "Where can I find an example of UCX Master Server programming?" A: Using UCX (or TCPware's UCX emulation), you will use what is called the "UCX Auxiliary Server" See the DEC TCP/IP Services manual "System Services and C Socket Programming". Appendix A.6 - "TCP/IP Server Accepting a Connection from the Auxiliary Server Example" - is a simple example. Basically your server program does the following: sock_fd = socket(UCX$C_AUXS, 0, 0) and now 'sock_fd' can be used with other socket calls (read/write/etc) To add this as a service in TCPware: 1) Write a STARTUP.COM file that will RUN your program 2) Add the service via: NETCU ADD SERVICE BG_TCP - /USER=SYSTEM - /INPUT=disk:[dir]STARTUP.COM If you were using an actual UCX system, you would add the service via: UCX> SET SERVICE - /USER=SYSTEM - /PROCESS= - /PORT= - /FILE=disk:[dir]STARTUP.COM For example: The TCP/IP server from the DEC TCP/IP programming guide is: #include #include #include #include "tcpware_include:ucx$inetdef.h" main() { int s; char *message = "Hello, world!\n"; s = socket(UCX$C_AUXS, 0, 0); write(s, message, strlen(message)); close(s); } Compile and link this with TCPware via: $ CC HELLO_WORLD.C $ LINK HELLO_WORLD,TCPWARE:UCX$IPC/LIB,SYS$INPUT/OPTIONS SYS$SHARE:VAXCRTL.EXE/SHARE Create STARTUP.COM containing: $ RUN SYS$SYSDEVICE:[USER]HELLO_WORLD.EXE Add as a service at port 7777 via: $ NETCU ADD SERVICE 7777 BG_TCP /USER=SYSTEM - /INPUT=SYS$SYSDEVICE:[USER]STARTUP.COM To verify the service is there: $ NETCU SHOW SERVICE TCPware(R) for OpenVMS NETCP Services: Protocol Port Active Limit Connects Errors Image -------- ---- ------ ----- -------- ------ ----- <...various TCPware services...> BG_TCP 7777 0 none 0 0 Use the service (from another host): (Merope) $ TELNET THETA 7777 %TCPWARE_TELNET-I-TRYING, trying THETA.process.com,7777 (192.42.95.72,7777) ... %TCPWARE_TELNET-I-ESCCHR, escape (attention) character is "^\" Hello, world! ---------------- end of UCX auxiliary server memo ---------------------------