Wyv9 ?Dy ù ? C Network Application Development Client Software Design 1 Chapter 3: Client Software Design Chapter goal: ? Algorithm and issues ? Concurrency in client ? Client examples Wyv9 ?Dy ù ? C Network Application Development Client Software Design 2 Chapter 3: Client Software Design Chapter goal: ? Algorithm and issues ? Concurrency in client ? Client examples Wyv9 ?Dy ù ? C Network Application Development Client Software Design 3 Learning algorithm instead of details ? An application that uses TCP/IP must specify many details about the desired communication. ? Knowing the low-level details of all possible socket functions and their exact parameters does not provide programmers with an understanding of how to build well-designed, distributed program. ? General understanding of the functions used for network communication is important. ? If the programmer knows what the program should do, finding out how to do it is straightforward. ? Although programmers need to understand the conceptual capabilities of the protocol interface, they should concentrate on learning about ways to structure communicating programs instead of memorizing the details of a particular interface. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 4 Client architecture ? Clients are conceptually simpler than servers. ? Most client does not explicitly handle concurrent interaction with multiple servers. ? Most client executes as a conventional app program. ? Most client does not need to enforce protections. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 5 Identify a server ? Several methods to find a server’s IP address and protocol port number: ? Domain name or IP address as a constant in program; ? Requiring user to identify; ? From stable storage; ? Using a separate protocol to find; ? Allowing the user to specify a server address when invoking client software makes the client program more general and makes it possible to change server locations. ? Building client that accepts a server address as an argument makes it easy to build extended versions of the software that use other ways to find the server address. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 6 Parsing an address argument ? Client can use domain name or IP address to identify the server machine. ? To determine whether the user has specified a name or an address, the client scans the argument. ? Client sometimes need additional information, such as protocol port. ? Two arguments: merlin.cs.purdue.edu smtp ? Single argument: merlin.cs.purdue.edu:smtp ? Consistency is important Wyv9 ?Dy ù ? C Network Application Development Client Software Design 7 Looking up a domain name ? A client must specify the address of a server using structure of sockaddr_in. ? Doing so means converting an address in dotted decimal notation (or domain name) into a 32-bit IP address. ? Function inet_addr takes an ASCII string that contains a dotted decimal address and returns the equivalent IP address in binary. ? Function gethostbyname takes an ASCII string that contains the domain name for a machine, and returns the address of a hostent structure that contains, among other strings, the host’s IP address in binary. ? The hostent structure is declared in include file winsock.h. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 8 hostent structure stuct hostent { char FAR* h_name; /*official host name */ char FAR* FAR* h_aliases; /*other aliases */ short h_addrtype; /*address type */ short h_lengty; /*address length */ char FAR* FAR* h_addr_list; /*list of address */ }; #define h_addr h_addr_list[0] ? Fields that contain names and addresses must be lists because of multiple interfaces. ? h_addr refer to the first location in the host address list. ? A program can use h_addr as if it were a field of structure hostent. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 9 Example for gethostbyname stuct hostent *hptr; char *examplenam=“merlin.cs.purdue.edu”; if (hptr=gethostbyname(example)){ /* IP address is now in hptr->h_addr*/ }else { /*error in name-handle it*/ } ? Successfully call, gethostbyname returns a pointer to a valid hostent struture. Otrerwise, ? Returns a NULL pointer. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 10 Looking up a well-known port by name ? Look up the protocol port for specific service. ? getservbyname ? Two arguments: ? A string that specifies the desired service ? A string that specifies the protocol being used ? Returns a pointer to a structure of type servent. ? Defined in include file winsock.h. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 11 servent structure stuct servent { char FAR* s_name; /*official service name */ char FAR* FAR* s_aliases; /*other aliases */ short s_port; /*port for this service */ char FAR* s_proto; /*protocol to use */ }; Wyv9 ?Dy ù ? C Network Application Development Client Software Design 12 Example stuct servent *sptr; if (sptr=getservbyname(“smtp”, “tcp”)){ /* port number is now in sptr->s_port*/ }else { /*error occurred-handle it*/ } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 13 Port numbers and network byte order ? getservbyname returns the protocol port for the service in network byte order. ? It is sufficient to understand that getservbyname returns the port value in exactly the form needed for use in the sockaddr_in structure. ? But, the representation may not agree with the local machine’s usual representation. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 14 Looking up a protocol by name ? getprotobyname returns the address of a structure of type protoent. ? Contained in winsock.h. stuct protoent { char FAR* p_name; /*official protocol name */ char FAR* FAR* p_aliases; /*list of aliases allowed*/ short p_proto; /*official protocol number*/ }; Wyv9 ?Dy ù ? C Network Application Development Client Software Design 15 Example stuct protoent *pptr; if (pptr=getprotobyname(“udp”)){ /* official protocol number is now in pptr->p_proto*/ }else { /*error occurred-handle it*/ } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 16 The TCP client algorithm 1. Find the IP address and protocol port number of the server with which communication is desired. 2. Allocate a socket. 3. Specify that the connection needs an arbitrary, unused protocol port on the local machine, and allow TCP to choose one. 4. Connect the socket to the server. 5. Communicate with the server using the application-layer protocols. 6. Close the connection. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 17 Allocating a socket #include <winsock.h> SOCKET s; s=socket(PF_INET, SOCK_STREAM, 0 ); Wyv9 ?Dy ù ? C Network Application Development Client Software Design 18 Choosing a local protocol port number ? The client does not care which port it uses as long as : ? The port does not conflict with the ports that other applications on the machine are already using. ? The port has not been assigned to a well-known service. ? The choice of a local port that meets the criteria listed above happens as a side- effect of the connect call. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 19 Choosing a local IP address ? A client must choose a local IP address as well as a local port number. ? Gateways (routers) or multihomed hosts have multiple IP addresses. ? The difficulty in choosing an IP address arises because the correct choice depends on routing and applications seldom have access to routing information. ? Problem: the IP source address in an outgoing datagram should match the IP address of the network interface over which IP routes the datagram. ? Using an incorrect address violates the specification, makes network management difficult and confusing, and makes the program less reliable. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 20 Choosing a local IP address ? To solve the problem, the socket functions make it possible for an application to leave the local IP address field unfilled and to allow TCP/IP software to choose a local IP address automatically at the time the client connects to a server. ? Because choosing the correct local IP address requires the application to interact with IP routing software, TCP client software usually leaves the local endpoint address unfilled, and allows TCP/IP software to select the correct local IP address and an unused local protocol port number automatically. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 21 Connecting a TCP socket to a server ? connect function ? connect forces the initial TCP 3-way handshaking. ? The call to connect does not return until a TCP connection has been established or TCP reaches timeout threshold and gives up. ? The call returns 0 if the connection attempt succeeds or SOCKET_ERROR if it fails. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 22 Connecting a TCP socket to a server connect(socket,remaddr,remaddrlen); ? Socket is the descriptor for a socket; ? Remaddr is the address of a structure of type sockaddr_in that specifies the remote endpoint to which a connection is desired; ? Remaddrlen is the length of remaddr. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 23 Connecting a TCP socket to a server ? connect performs four tasks: ? Test to ensure that the specified socket is valid and that it has not already been connected; ? Fills in the remote endpoint address in the socket from the second argument; ? Chooses a local endpoint address for the connection (IP address and protocol port number) if the socket does not have one; ? Initiates a TCP connection, and returns a value to tell the caller whether the connection succeeded. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 24 Communicating with the server using TCP ? Usually request-response interaction. ? A client call send to transmit each request and recv to await a response. ? For example: Wyv9 ?Dy ù ? C Network Application Development Client Software Design 25 Communicating with the server using TCP #define BLEN 120 /*buffer length to use */ char *req=“request of some sort”; char buf[BLEN]; /*buffer for answer */ char *bptr; /*pointer to buffer */ int n; /*number of bytes read */ int buflen; /*space left in buffer */ Bptr=buf; buflen=BLEN; /*send request*/ send(s,req,strlen(req),0); /*read response (may come in many pieces)*/ n=recv(s,bptr,buflen,0); while(n!=SOCKET_ERROR && n!=0){ bptr+=n; buflen-=n; n=recv(s,bptr,buflen,0); } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 26 Reading response from a TCP connection ? TCP is not a block-oriented protocol, is a stream-oriented protocol. ? TCP guarantees to deliver the sequence of bytes that the sender writes, but it does not guarantee to deliver them in the same grouping as they were wirten. ? Because TCP does not preserve record boundaries, any program that reads from a TCP connection must be prepared to accept data a few bytes at a time. ? This rule holds even if the sending application writes data in large blocks. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 27 Closing a TCP connection ? closesocket terminates the connection gracefully and deallocate the socket. ? Closing a connection is not simple because of full-duplex. ? Closing a connection usually requires coordination among the client and server. ? To solve the connection shutdown problem, most implementations of the socket interface include an additional primitive that permits application to shut down a TCP connection in one direction. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 28 A partial close operation ? shutdown function takes two parameters: ? A socket descriptor ? Direction errcode = shutdown( s, direction); Integer: 0-no further input is allowed; 1-no further output is allowed; 2-both direction. ? Advantage: end-of-file signal. ? The partial close mechanism removes ambiguity for application protocols that transmit arbitrary amounts of information in response to a request. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 29 Programming a UDP client- algorithm 1. Find the IP address and protocol port number of the server with which communication is desired. 2. Allocate a socket. 3. Specify that the communication needs an arbitrary, unused protocol port on the local machine, and allow UDP to choose one. 4. Specify the server which messages to sent. 5. Communicate with the server using the application-layer protocol. 6. Close the connection. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 30 Connected and unconnected UDP sockets ? Two basic UDP socket mode: ? Connected ? Unconnected ? Advantages: ? Connected: the application need specify the server only once. ? Unconnected: flexibility, communicate with different servers. ? UDP sockets can be connected, making it conventional to interact with a specific server, or they can be unconnected, making it necessary for the application to specify the server’s address each time it sends a message. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 31 Using connect with UDP ? The connect call does not initiate any packet exchange, nor does it test the validity of the remote endpoint address. ? It merely records the remote endpoint information in the socket data structure for later use. ? Even if connect call succeeds, it does not mean that the remote endpoint address is valid or that the server if reachable. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 32 Communicating with a server using UDP ? UDP provides message transfer. ? Connect mode ? Using send and recv to send or receive a message. ? UDP client does not need to make repeated calls to recv to obtain a single message. ? UDP does not need repeated call to recv Wyv9 ?Dy ù ? C Network Application Development Client Software Design 33 Closing a socket that uses UDP ? Calls closesocket like TCP, but does not inform the remote endpoint. ? Partial close for UDP ? shutdown can be used with a connected UDP socket to stop further transmission in a given direction. ? Unlike TCP, shutdown does not send any messages to the other side. ? It merely marks the local socket as unwilling to transfer data in the direction(s) specified. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 34 About UDP unreliability ? Client software that uses UDP must implement reliability with techniques like packet sequencing, acknowledgements, timeout, and efficient for an internet environment requires consideration expertise. ? How to build reliable apps over UDP? ? Home work…… Wyv9 ?Dy ù ? C Network Application Development Client Software Design 35 Chapter 3: Client Software Design Chapter goal: ? Algorithm and issues ? Concurrency in client ? Client examples Wyv9 ?Dy ù ? C Network Application Development Client Software Design 36 Advantages of concurrency ? Server ? Response time ? Potential deadlocks ? Multiprotocol & multiservice servers ? portability ? Client ? Easier to program: Separate functionality into conceptually separate components ? Easier to maintain and extend: modular ? Can contact several servers at the same time ? Allow users to change parameters, inquire about the client status, or control processing dynamically ? The key advantage lies in asynchrony. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 37 Motivation for exercising control ? Separate control functions from normal processing ? Uncertain response time and response size ? Most client merely waits until a response arrives ? Deadlock may occur ? Concurrency can help ? Concurrent client can permit user to continue interact with the client while the client waits for a response ? User can find out whether any data has been received, choose to send a different request, or terminate ? Separating client control from normal processing allows a user to interact with a client even if the normal input for the client comes from a file. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 38 Concurrent contact with multiple servers ? Concurrency can allow a single client to contact several servers at the same time and report to the user as soon as it receives from any of them ? For example Wyv9 ?Dy ù ? C Network Application Development Client Software Design 39 Implementing concurrent clients ? Two basic approaches ? The client divides into two or more threads that each handle one function ? The client consists of a single thread that uses select to handle multiple input and output events asynchronously Wyv9 ?Dy ù ? C Network Application Development Client Software Design 40 Implementing concurrent clients ? Two basic approaches ? The client divides into two or more threads that each handle one function ? The client consists of a single thread that uses select to handle multiple input and output events asynchronously control input output Control descriptor input TCP socket output Client threads Operating system Wyv9 ?Dy ù ? C Network Application Development Client Software Design 41 Implementing concurrent clients ? Two basic approaches ? The client divides into two or more threads that each handle one function ? The client consists of a single thread that uses select to handle multiple input and output events asynchronously client input TCP socket 1 TCP socket 2 TCP socket n Client thread Operating system … Wyv9 ?Dy ù ? C Network Application Development Client Software Design 42 Chapter 3: Client Software Design Chapter goal: ? Algorithm and issues ? Concurrency in client ? Client examples Wyv9 ?Dy ù ? C Network Application Development Client Software Design 43 Example client software ? Importance of small examples ? Easy to understand ? Highlight fundamental algorithm ? Intuitive understanding ? Hiding details ? Modular program ? Easy to port ? Procedures raise the level of the language-reuse ? Use of procedures is important when building C/S programs ? Reduce the chance for error ? Reuse the code ? Isolate the OS dependency ? The first step of designing a procedure lib is abstraction ? The procedure abstraction allows programmers to define high-level operations, share code among applications. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 44 Implementation of ConTCP /* conTCP.cpp - connectTCP */ #include <winsock.h> SOCKET connectsock(const char *, const char *, const char *); /*---------------------------------------------------- * connectTCP - connect to a specified TCP service * on a specified host *-------------------------------------------------- */ SOCKET connectTCP(const char *host, const char *service ) { return connectsock( host, service, "tcp"); } ? Place all the low level code into connectsock procedure Wyv9 ?Dy ù ? C Network Application Development Client Software Design 45 Implementation of ConUDP /* conUDP.cpp - connectUDP */ #include <winsock.h> SOCKET connectsock(const char *, const char *, const char *); /*------------------------------------------------------- * connectUDP - connect to a specified UDP service * on a specified host *-----------------------------------------------------*/ SOCKET connectUDP(const char *host, const char *service ) { return connectsock(host, service, "udp"); } ? Used to establish a connected socket that uses UDP Wyv9 ?Dy ù ? C Network Application Development Client Software Design 46 A procedure that forms connections /* consock.cpp - connectsock */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <winsock.h> #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif /* INADDR_NONE */ void errexit(const char *, ...); /*------------------------------------------------------------------------ * connectsock - allocate & connect a socket using TCP or UDP *------------------------------------------------------------------------ */ Wyv9 ?Dy ù ? C Network Application Development Client Software Design 47 A procedure that forms connections (cont.) SOCKET connectsock(const char *host, const char *service, const char *transport ) { struct hostent *phe; /* pointer to host information entry */ struct servent *pse; /* pointer to service information entry */ struct protoent *ppe; /* pointer to protocol information entry */ struct sockaddr_in sin;/* an Internet endpoint address */ int s, type; /* socket descriptor and socket type */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; Wyv9 ?Dy ù ? C Network Application Development Client Software Design 48 A procedure that forms connections (cont.) /* Map service name to port number */ if ( pse = getservbyname(service, transport) ) sin.sin_port = pse->s_port; else if ( (sin.sin_port = htons((u_short)atoi(service))) == 0 ) errexit("can't get \"%s\" service entry\n", service); /* Map host name to IP address, allowing for dotted decimal */ if ( phe = gethostbyname(host) ) memcpy(&sin.sin_addr, phe->h_addr, phe->h_length); else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) errexit("can't get \"%s\" host entry\n", host); /* Map protocol name to protocol number */ if ( (ppe = getprotobyname(transport)) == 0) errexit("can't get \"%s\" protocol entry\n", transport); Wyv9 ?Dy ù ? C Network Application Development Client Software Design 49 A procedure that forms connections (cont.) /* Use protocol to choose a socket type */ if (strcmp(transport, "udp") == 0) type = SOCK_DGRAM; else type = SOCK_STREAM; /* Allocate a socket */ s = socket(PF_INET, type, ppe->p_proto); if (s == INVALID_SOCKET) errexit("can't create socket: %d\n", GetLastError()); /* Connect the socket */ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR) errexit("can't connect to %s.%s: %d\n", host, service, GetLastError()); return s;} Wyv9 ?Dy ù ? C Network Application Development Client Software Design 50 A procedure that forms connections (cont.) /* errexit.cpp - errexit */ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <winsock.h> /*------------------------------------------------------------------------ * errexit - print an error message and exit *------------------------------------------------------------------------ */ /*VARARGS1*/ void errexit(const char *format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end(args); WSACleanup(); exit(1);} Wyv9 ?Dy ù ? C Network Application Development Client Software Design 51 Client examples-1 ? The DAYTIME service ? Obtain the day and time ? Available for both TCP and UDP, port 13 ? The TCP version uses the presence of a TCP connection to trigger output ? The UDP version needs the client to send a request Wyv9 ?Dy ù ? C Network Application Development Client Software Design 52 Implementation of a TCP client for DAYTIME /* TCPdtc.cpp - main, TCPdaytime */ #include <stdlib.h> #include <stdio.h> #include <winsock.h> void TCPdaytime(const char *, const char *); void errexit(const char *, ...); SOCKET connectTCP(const char *, const char *); #define LINELEN 128 #define WSVERS MAKEWORD(2, 0) /*------------------------------------------------------------------------ * main - TCP client for DAYTIME service *------------------------------------------------------------------------ */ Wyv9 ?Dy ù ? C Network Application Development Client Software Design 53 Implementation of a TCP client for DAYTIME (cont.) Int main(int argc, char *argv[]) { char *host = "localhost"; /* host to use if none supplied */ char *service = "daytime"; /* default service port */ WSADATA wsadata; switch (argc) { case 1: host = "localhost"; break; case 3: service = argv[2]; /* FALL THROUGH */ case 2: host = argv[1]; break; Wyv9 ?Dy ù ? C Network Application Development Client Software Design 54 Implementation of a TCP client for DAYTIME (cont.) default: fprintf(stderr, "usage: TCPdaytime [host [port]]\n"); exit(1); } if (WSAStartup(WSVERS, &wsadata) != 0) errexit("WSAStartup failed\n"); TCPdaytime(host, service); WSACleanup(); return 0; /* exit */ } /*------------------------------------------------------------------------ * TCPdaytime - invoke Daytime on specified host and print results *------------------------------------------------------------------------ */ Wyv9 ?Dy ù ? C Network Application Development Client Software Design 55 Implementation of a TCP client for DAYTIME (cont.) void TCPdaytime(const char *host, const char *service) { char buf[LINELEN+1]; /* buffer for one line of text */ SOCKET s; /* socket descriptor */ int cc; /* recv character count */ s = connectTCP(host, service); cc = recv(s, buf, LINELEN, 0); while( cc != SOCKET_ERROR && cc > 0) { buf[cc] = '\0'; /* ensure null-termination */ (void) fputs(buf, stdout); cc = recv(s, buf, LINELEN, 0); } closesocket(s); } Because the TCP stream service does not guarantee to deliver data in the same blocks that it was writen, an application receiving data from a TCP connection cannot depend on all data being delivered in a single transfer; it must repeatedly call recv until all data has been obtained. Wyv9 ?Dy ù ? C Network Application Development Client Software Design 56 Client examples-2 ? The TIME service ? Obtain the day and time from another machine similar to DAYTIME service ? Time and day information must be represented in Universal Coordinated Time ? TIME service is intended for use by programs that store or manipulate times ? Always specifies time in a 32-bit integer, representing the number of seconds since an epoch date ? TIME Uses midnight, January 1, 1900, as its epoch ? Available for both TCP and UDP, port 37 ? The TCP version uses the presence of a TCP connection to trigger output ? The UDP version needs the client to send a request ? TIME does not handle the problem of network latency Wyv9 ?Dy ù ? C Network Application Development Client Software Design 57 A UDP Client for the TIME service /* UDPtime.cpp - main */ #include <stdlib.h> #include <stdio.h> #include <time.h> #include <winsock.h> #define BUFSIZE 64 #define WSVERS MAKEWORD(2, 0) #define WINEPOCH 2208988800 /* Windows epoch, in UCT secs */ #define MSG "what time is it?\n" SOCKET connectUDP(const char *, const char *); Wyv9 ?Dy ù ? C Network Application Development Client Software Design 58 A UDP Client for the TIME service (cont.) void errexit(const char *, ...); /*------------------------------------------------------------------------ * main - UDP client for TIME service that prints the resulting time *------------------------------------------------------------------------ */ int main(int argc, char *argv[]) { char *host = "localhost"; /* host to use if none supplied */ char *service = "time"; /* default service name */ time_t now; /* 32-bit integer to hold time */ SOCKET s; /* socket descriptor */ int n; /* recv count */ WSADATA wsadata; Wyv9 ?Dy ù ? C Network Application Development Client Software Design 59 A UDP Client for the TIME service (cont.) switch (argc) { case 1: host = "localhost"; break; case 3: service = argv[2]; /* FALL THROUGH */ case 2: host = argv[1]; break; default: fprintf(stderr, "usage: UDPtime [host [port]]\n"); exit(1); } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 60 A UDP Client for the TIME service (cont.) if (WSAStartup(WSVERS, &wsadata)) errexit("WSAStartup failed\n"); s = connectUDP(host, service); (void) send(s, MSG, strlen(MSG), 0); /* Read the time */ n = recv(s, (char *)&now, sizeof(now), 0); if (n == SOCKET_ERROR) errexit("recv failed: recv() error %d\n", GetLastError()); WSACleanup(); now = ntohl((u_long)now); /* put in host byte order */ now -= WINEPOCH; /* convert UCT to Windows epoch*/ printf("%s", ctime(&now)); return 0; /* exit */ } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 61 Client examples-3 ? The ECHO service ? ECHO service for both TCP and UDP port 7 ? Merely returns all the data received from a client ? Important tools for: ? Test reachability ? Debug protocol software ? Identify routing problem Wyv9 ?Dy ù ? C Network Application Development Client Software Design 62 A TCP Client for the ECHO service /* TCPecho.cpp - main, TCPecho */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <winsock.h> void TCPecho(const char *, const char *); void errexit(const char *, ...); SOCKET connectTCP(const char *, const char *); #define LINELEN 128 #define WSVERS MAKEWORD(2, 0) Wyv9 ?Dy ù ? C Network Application Development Client Software Design 63 A TCP Client for the ECHO service (cont.) /*------------------------------------------------------------------------ * main - TCP client for ECHO service *----------------------------------------------------------------------- */ void main(int argc, char *argv[]) { char *host = "localhost"; /* host to use if none supplied */ char *service = "echo"; /* default service name */ WSADATA wsadata; switch (argc) { case 1: host = "localhost"; break; case 3: service = argv[2]; /* FALL THROUGH */ Wyv9 ?Dy ù ? C Network Application Development Client Software Design 64 A TCP Client for the ECHO service (cont.) case 2: host = argv[1]; break; default: fprintf(stderr, "usage: TCPecho [host [port]]\n"); exit(1); } if (WSAStartup(WSVERS, &wsadata) != 0) errexit("WSAStartup failed\n"); TCPecho(host, service); WSACleanup(); exit(0); } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 65 A TCP Client for the ECHO service (cont.) /*------------------------------------------------------------------------ * TCPecho - send input to ECHO service on specified host and print reply *------------------------------------------------------------------------ */ void TCPecho(const char *host, const char *service) { char buf[LINELEN+1]; /* buffer for one line of text */ SOCKET s; /* socket descriptor */ int cc, outchars, inchars; /* characters counts */ s = connectTCP(host, service); while (fgets(buf, sizeof(buf), stdin)) { buf[LINELEN] = '\0'; /* ensure line null-termination */ outchars = strlen(buf); (void) send(s, buf, outchars, 0); Wyv9 ?Dy ù ? C Network Application Development Client Software Design 66 A TCP Client for the ECHO service (cont.) /* read it back */ for (inchars = 0; inchars < outchars; inchars += cc) { cc = recv(s, &buf[inchars], outchars-inchars, 0); if (cc == SOCKET_ERROR) errexit("socket recv failed: %d\n", GetLastError()); } fputs(buf, stdout); } closesocket(s); } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 67 A UDP Client for the ECHO service /* UDPecho.cpp - main, UDPecho */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <winsock.h> void UDPecho(const char *, const char *); void errexit(const char *, ...); SOCKET connectUDP(const char *, const char *); #define LINELEN 128 #define WSVERS MAKEWORD(2, 0) Wyv9 ?Dy ù ? C Network Application Development Client Software Design 68 A UDP Client for the ECHO service (cont.) /*------------------------------------------------------------------------ * main - UDP client for ECHO service *------------------------------------------------------------------------ */ void main(int argc, char *argv[]) { char *host = "localhost"; char *service = "echo"; WSADATA wsadata; switch (argc) { case 1: host = "localhost"; break; case 3: service = argv[2]; /* FALL THROUGH */ Wyv9 ?Dy ù ? C Network Application Development Client Software Design 69 A UDP Client for the ECHO service (cont.) case 2: host = argv[1]; break; default: fprintf(stderr, "usage: UDPecho [host [port]]\n"); exit(1); } if (WSAStartup(WSVERS, &wsadata)) errexit("WSAStartup failed\n"); UDPecho(host, service); WSACleanup(); exit(0); } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 70 A UDP Client for the ECHO service (cont.) /*------------------------------------------------------------------------ * UDPecho - send input to ECHO service on specified host and print reply *------------------------------------------------------------------------ */ void UDPecho(const char *host, const char *service) { char buf[LINELEN+1]; /* buffer for one line of text */ SOCKET s; /* socket descriptor */ int nchars; /* read count*/ s = connectUDP(host, service); while (fgets(buf, sizeof(buf), stdin)) { buf[LINELEN] = '\0'; /* ensure null-terminated */ nchars = strlen(buf); (void) send(s, buf, nchars, 0); Wyv9 ?Dy ù ? C Network Application Development Client Software Design 71 A UDP Client for the ECHO service (cont.) if (recv(s, buf, nchars, 0) < 0) errexit("recv failed: error %d\n", GetLastError()); fputs(buf, stdout); } } ? Find out the difference between TCP and UDP version? Wyv9 ?Dy ù ? C Network Application Development Client Software Design 72 Concurrent Client example ? An example concurrent client that uses ECHO service ? Single thread ? Uses the ECHO service to measure network throughput to a set of machines Wyv9 ?Dy ù ? C Network Application Development Client Software Design 73 Concurrent client /* TCPtecho.cpp - main, TCPtecho, reader, writer, mstime */ #include <stdio.h> #include <string.h> #include <time.h> #include <winsock.h> #define BUFSIZE 4096 /* write buffer size */ #define CCOUNT 64*1024 /* default character count */ #define WSVERS MAKEWORD(2, 0) #define MIN(x, y) ((x)>(y) ? (y) : (x)) #define USAGE "usage: TCPtecho [ -c count ] host1 host2...\n" Wyv9 ?Dy ù ? C Network Application Development Client Software Design 74 Concurrent client (cont.) struct hdat { char *hd_name; /* host name */ SOCKET hd_sock; /* host socket descriptor */ unsigned hd_rc; /* recv character count */ unsigned hd_wc; /* send character count */ } hdat[FD_SETSIZE]; /* fd to host name mapping */ char buf[BUFSIZE]; /* read/write data buffer */ void TCPtecho(fd_set *, int); int reader(struct hdat *, fd_set *); void writer(struct hdat *, fd_set *); void errexit(const char *, ...); SOCKET connectTCP(const char *, const char *); long mstime(u_long *); Wyv9 ?Dy ù ? C Network Application Development Client Software Design 75 Concurrent client (cont.) /*------------------------------------------------------------------------ * main - concurrent TCP client for ECHO service timing *------------------------------------------------------------------------ */ void main(int argc, char *argv[]) { int ccount = CCOUNT; int i, hcount, fd; unsigned long one = 1; fd_set afds; WSADATA wsdata; hcount = 0; if (WSAStartup(WSVERS, &wsdata)) errexit("WSAStartup failed\n"); FD_ZERO(&afds); Wyv9 ?Dy ù ? C Network Application Development Client Software Design 76 Concurrent client (cont.) for (i=1; i<argc; ++i) { if (strcmp(argv[i], "-c") == 0) { if (++i < argc && (ccount = atoi(argv[i]))) continue; errexit(USAGE); } /* else, a host */ fd = connectTCP(argv[i], "echo"); if (ioctlsocket(fd, FIONBIO, &one)) { fprintf(stderr, "can't mark nonblocking (host %s): %d\n", argv[i], GetLastError()); continue; } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 77 Concurrent client (cont.) hdat[hcount].hd_name = argv[i]; hdat[hcount].hd_sock = fd; hdat[hcount].hd_rc = hdat[hcount].hd_wc = ccount; ++hcount; FD_SET(fd, &afds); } TCPtecho(&afds, hcount); WSACleanup(); exit(0); } /*------------------------------------------------------------------------ * TCPtecho - time TCP ECHO requests to multiple servers *----------------------------------------------------------------------*/ Wyv9 ?Dy ù ? C Network Application Development Client Software Design 78 Concurrent client (cont.) void TCPtecho(fd_set *pafds, int hcount) { fd_set rfds, wfds; /* read/write fd sets */ fd_set rcfds, wcfds; /* read/write fd sets (copy) */ int fd, hndx, i; for (i=0; i<BUFSIZE; ++i) /* echo data */ buf[i] = 'D'; memcpy(&rcfds, pafds, sizeof(rcfds)); memcpy(&wcfds, pafds, sizeof(wcfds)); (void) mstime((u_long *)0); /* set the epoch */ while (hcount) { memcpy(&rfds, &rcfds, sizeof(rfds)); memcpy(&wfds, &wcfds, sizeof(wfds)); Wyv9 ?Dy ù ? C Network Application Development Client Software Design 79 Concurrent client (cont.) if (select(FD_SETSIZE, &rfds, &wfds, (fd_set *)0, (struct timeval *)0) == SOCKET_ERROR) errexit("select failed: error %d\n", GetLastError()); for (hndx=0; hndx<hcount; ++hndx) { fd = hdat[hndx].hd_sock; if (FD_ISSET(fd, &rfds)) if (reader(&hdat[hndx], &rcfds) == 0) { /* this host is done */ for (i=hndx+1; i<hcount; ++i) hdat[i-1]=hdat[i]; hcount--; continue; } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 80 Concurrent client (cont.) if (FD_ISSET(fd, &wfds)) writer(&hdat[hndx], &wcfds); } } } /*------------------------------------------------------------------------ * reader - handle ECHO reads *------------------------------------------------------------------------ */ int reader(struct hdat *phd, fd_set *pfdset) { u_long now; int cc; cc = recv(phd->hd_sock, buf, sizeof(buf), 0); Wyv9 ?Dy ù ? C Network Application Development Client Software Design 81 Concurrent client (cont.) if (cc == SOCKET_ERROR) errexit("recv: error %d\n", GetLastError()); if (cc == 0) errexit("recv: premature end of file\n"); phd->hd_rc -= cc; if (phd->hd_rc > 0) return 1; (void) mstime(&now); printf("%s: %d ms\n", phd->hd_name, now); (void) closesocket(phd->hd_sock); FD_CLR(phd->hd_sock, pfdset); return 0; } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 82 Concurrent client (cont.) /*------------------------------------------------------------------------ * writer - handle ECHO writes *------------------------------------------------------------------------ */ void writer(struct hdat *phd, fd_set *pfdset) { int cc; cc = send(phd->hd_sock, buf, MIN(sizeof(buf), phd->hd_wc), 0); if (cc == SOCKET_ERROR) errexit("send: error number %d\n", GetLastError()); phd->hd_wc -= cc; if (phd->hd_wc == 0) { (void) shutdown(phd->hd_sock, 1); FD_CLR(phd->hd_sock, pfdset); } } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 83 Concurrent client (cont.) /*------------------------------------------------------------------------ * mstime - report the number of clock ticks elapsed since mstime(0) call *------------------------------------------------------------------------ */ long mstime(u_long *pms) { static unsigned long epoch; unsigned long now; now = clock(); if (pms == 0) { epoch = now; return 0; } *pms = now - epoch; return *pms; } Wyv9 ?Dy ù ? C Network Application Development Client Software Design 84 Summary We have Learned: ? Algorithm and issues ? Concurrency in client ? Client examples