1 / 111

Client/Server Distributed Systems

Client/Server Distributed Systems. 240-322, Semester 1, 2005-2006. Objectives introduce sockets look at iterative servers (using TCP) look at clients (using TCP). 7. Sockets (1) Chapter 4, Brown. Overview. 1. Socket Definition 2. Socket Data Structures

paxton
Download Presentation

Client/Server Distributed Systems

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Client/Server Distributed Systems 240-322, Semester 1, 2005-2006 • Objectives • introduce sockets • look at iterative servers (using TCP) • look at clients (using TCP) 7. Sockets (1)Chapter 4, Brown

  2. Overview 1. Socket Definition 2. Socket Data Structures 3. Connection-oriented Services 4. Iterative Servers 5. Clients 6. Clients of System Services 7. More Details

  3. 1. Socket Definition • A socket is an ‘end-point’ for communication at the transport layer. • for TCP, a socket is like a telephone • for UDP, a socket is like a mailbox • There is a socket at each end of the communication: • one used by the client, one used by the server

  4. 2. Socket Data Structures • There are several kinds of data structure for sockets, depending on their use: • as end-points between processes on the same machine • very rarely used • as end-points between networked processes

  5. Networked Socket Data Structures struct sockaddr_in { short sin_family; /* AF_INET in IPv4*/ u_short sin_port; /* port no. */ struct in_addr sin_addr; /* IP address */ char sin_zero[8]; /* padding of O’s */};struct in_addr { u_long s_addr; /* nastier in SunOS */}; • Details in /usr/include/netinet/in.h continued

  6. Due to the two possible uses of sockets, most functions require that sockets be cast into a ‘generic’ socket data type: struct sockaddr { u_short sa_family; char sa_data[14];} • see /usr/include/sys/socket.h

  7. Socket Types • Many socket functions also require a socket type: • SOCK_STREAM • for connection-oriented transport, e.g. TCP • SOCK_DGRAM • for connectionless transport, e.g. UDP • SOCK_RAW • others

  8. 3. Connection-oriented Servers • We will use TCP for connection-oriented communication. • Two basic kinds of server: • iterative: the server deals with one client at once • concurrent: the server can deal with multiple clients at once

  9. Basic client-server Operation Server dealt with by my tcp_serv_sock() Create socket with socket() Client Initialise serveraddress details Initialise socket address data structure Bind server address to socket with bind() Create socket with socket() Listen for connections with listen() Connect to server’sport with connect() blocks until connection from a client data (request) read() write() process request data (reply) read() write()

  10. 3.1. tcp_serv_sock() • My function which hides the first 4 stages of the server’s operation: • contains calls to socket(), bind() and listen() • The binding of the server’s address to the socket (stage 3) requires a sockaddr_in struct to be initialised.

  11. sin_family sin_port sin_addr sin_zero[8] Initialising a sockaddr_in struct for a server serv_addr AF_INET htons(port) htonl(INADDR_ANY) pad with 0’s continued

  12. Notes • The port number must be > 1023 if the server is user-defined. • INADDR_ANY means that the socket will work with all the network interfaces (i.e. network cards) on the machine. • nothing to do with client addresses

  13. tcp_serv_sock() int tcp_serv_sock(int port){ int sockfd; struct sockaddr_in serv_addr; /* create a TCP socket */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "Could not open a socket"); exit(1); } : continued

  14. /* initialise socket address data struct */ memset(&serv_addr, 0, sizeof(serv_addr)); /* bzero((char *)&serv_addr, sizeof(serv_addr)); */ serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(port); : continued

  15. /* bind socket to address */ if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { fprintf(stderr, "Could not bind socket to address\n"); exit(1); } /* Listen for incoming connections */ if (listen(sockfd, 5) < 0) { fprintf(stderr, "listen error\n"); exit(1); } return sockfd;}

  16. 3.1.1. socket() • Create a socket:#include <sys/types.h>#include <sys/socket.h>int socket(int family, int type, int protocol); • Return a socket descriptor if ok, -1 on error. continued

  17. family is one of: • AF_INET, AF_UNIX, and others • type is one of: • SOCK_STREAM, SOCK_DGRAM, and others • If protocol is 0 it means: • “let the system choose the protocol based on the supplied family and type information”

  18. 3.1.2. bind() • Bind an address to a socket:#include <sys/types.h>#include <sys/socket.h>int bind(int sockfd, struct sockaddr *myaddr, int addrlen); • Returns 0 if ok, -1 on error. • For more info. use “man 2 bind”

  19. 3.1.3. listen() • Listen for incoming connections:#include <sys/types.h>#include <sys/socket.h>int listen(int sockfd, int backlog); • Returns 0 if ok, -1 on error. continued

  20. backlog is how many connection requests from clients can be queued by the system while it waits for the server to execute an accept() call.

  21. 4. An Iterative Server • An iterative server which uses a TCP connection can now be outlined: • it sets up its socket using tcp_serv_sock() • it uses accept() to accept a connection • it calls the user-defined do_something() to do the server task • when do_something() is finished, it can accept another connection

  22. Outline Code #define PORT 1666int main(){ int rdsock, cdsock; : rdsock = tcp_serv_sock(PORT); while(1) { cdsock = accept(rdsock, ...); if (cdsock < 0) fprintf(stderr, “accept failed\n”); else {do_something(cdsock, ...); close(cdsock); } } return 0;}

  23. 4.0.1. accept() • Accept a client connection:#include <sys/types.h>#include <sys/socket.h>int accept(int sockfd, struct sockaddr *peer, int *addrlen); • Returns a socket descriptor if ok, -1 on error. continued

  24. accept() removes the first connection request from the listen queue attached to rdsock. • accept() returns a new socket (cdsock) for 1-1 communication between the server and client. • rdsock = rendezvous socket descriptorcdsock = connection socket descriptor continued

  25. peer is usually a pointer to a sockaddr_in struct (cast to sockaddr *) • peer is assigned details about the accepted client • The value in addrlen changes: • its input value is the size of the sockaddr_in struct • its output value is the actual size of the peer details

  26. Code Fragment struct sockaddr_in client;int client_len; :client_len = sizeof(client);cdsock = accept(rdsock, (struct sockaddr *)&client, &client_len); :

  27. 4.0.2. do_something() • The server-specific functionality: • e.g. “hangman” game code • It will use read() and write() to communicate with the client through cdsock. • The client and server must agree on the order of their read() and write()’s. continued

  28. The communication possible with read() and write()’s is a stream of characters (bytes): • the client and server must agree on how a ‘message’ is represented by a sequence of characters (bytes) • e.g. use a ‘$’ or ‘\n’ to end a ‘message’

  29. 4.1. Example: A Daytime Server • The daytime server returns the current time on the server when requested by a client. • It runs on takasila, listening at port 1666 • 1666 is not used in /etc/services • It expects no input from the client. It outputs the time and then closes the connection.

  30. day_serv.c #include <stdio.h>#include <string.h>/* #include <bstring.h> */#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <time.h> /* time funcs */#include <unistd.h>#define PORT 1666int tcp_serv_sock(int port); : continued

  31. int main(){ int rdsock, cdsock, client_len; struct sockaddr_in client; time_t now; char *now_str; rdsock = tcp_serv_sock(PORT); while(1) { client_len = sizeof(client); cdsock = accept(rdsock, (struct sockaddr *)&client, &client_len); : continued

  32. if (cdsock < 0) fprintf(stderr, “accept failed\n”); else {time(&now); now_str = ctime(&now); write(cdsock, now_str, strlen(now_str)); close(cdsock); } } return 0;} application specific

  33. Running day_serv.c Sun OS also requires:-lnsl -lsocket on takasila $ gcc -Wall -o day_serv day_serv.c$ ./day_serv &[1] 1701$ netstat -a | grep 1666$ ...$ kill -9 1701$ netstat -a | grep 1666/* port will not be released immediately */

  34. Using day_serv • Use telnet to open a connection:$ telnet takasila 1666Trying 172.30.0.82...Connected to takasila.coe.psu.ac.th.Escape character is '^]'.Wed May 4 11:15:34 2005Connection closed by foreign host.$ I did this from fivedots

  35. 4.2. Example: An Echo Server • The echo server reads the lines sent by the client, and echoes them back, converted into upper case. • A line ends with ‘\n’, and no line is longer than 128 characters. • An empty line terminates the connection. • The server runs on takasila, listening at port 1667.

  36. echo_serv.c #include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <unistd.h>#include <ctype.h> /* for toupper() */#define PORT 1667#define BUFSIZE 128int tcp_serv_sock(int port); : continued

  37. int main(){ int rdsock, cdsock, client_len; struct sockaddr_in client; rdsock = tcp_serv_sock(PORT); while(1) { client_len = sizeof(client); cdsock = accept(rdsock, (struct sockaddr *)&client, &client_len); : continued

  38. if (cdsock < 0) fprintf(stderr, “accept failed\n”); else {echo_upper(cdsock); close(cdsock); } } return 0;} application specific part continued

  39. void echo_upper(int sd){ char buf[BUFSIZE]; int n; while (((n = read(sd, buf, sizeof(buf)) != 0) && (!end_input(buf, n))) if (n < 0) fprintf(stderr, “echo read error\n”); else {/* buf[n] = ‘\0’; printf(“n: %d, buf: \”%s\”\n”, n, buf);*/ touppers(buf); if (write(sd, buf, n) < 0) fprintf(stderr, “echo write error\n”); }} continued

  40. void touppers(char buf[]){ int i = 0; while (buf[i] != ‘\n’) { buf[i] = toupper(buf[i]); i++; }}

  41. int end_input(char buf[], int len)/* Check if buf[] contains the characters meaning end-of-input for this server. Return 1 if true.*/{ if ((len == 2) && (buf[0] == ‘\015’) && (buf[1] == ‘\n’)) return 1; if ((len == 1) && (buf[0] == ‘\n’)) return 1; return 0;}

  42. Three Input Termination Cases • The client socket can close due to an error: • read() returns < 0 • The client socket can be closed by the client: • read() returns 0 • The client can send a newline only: • test with end_input() • check for telnet output (and other programs) which includes a carriage return (‘\015’) before the newline.

  43. Running echo_serv.c on takasila $ gcc -Wall -o echo_serv echo_serv.c$ ./echo_serv &[1] 1944$ netstat -a | grep 1667$ ...$ kill -9 1944$ netstat -a | grep 1667/* port will not be released immediately */

  44. Using echo_serv • Use telnet to open a connection:$ telnet takasila 1667Trying 172.30.0.82...Connected to takasila.coe.psu.ac.th.Escape character is '^]'.helloHELLOgoodbyeGOODBYEConnection closed by foreign host.$ on fivedots I typed a newline.

  45. 4.3. Problems with read() / write() • Over a network, read() / write() may not be able to read / write all the requested chars • due to bandwidth restrictions • due to network load e.g. n1 = read(sd, buf, 1023);n1 assigned 1000 continued

  46. Must call read() / write() again until the requested number of characters have been obtained. • Sometimes reading in the server should stop when a special character is read (e.g. a ‘\n’). continued

  47. One problem: • the code cannot rely on a ‘termination’ character (e.g. ‘\n’) being the last character • another separate message may follow it in the socket queue • reading N characters can read all of the first message and some of the next one queue sd a b c \n a b c d e \n read(sd, buf, 5); buf is assigned "a b c \n a" continued

  48. The problems continues: • a message may be split into smaller packets at the IP level • e.g. the message sent as "abcde\n" arrives as two packets "abc" and "de\n" • the read() call only gets the first packet, without a '\n' queue sd a b c d e \n read(sd, buf, 6); buf is assigned "a b c"

  49. 4.3.1. readline() • User-defined function that reads a stream of characters upto, and including, a ‘\n’. • It adds a ‘\0’ like fgets(), so that string functions can use the line directly. • readline() uses read() to read one character (byte) at a time • very slow

  50. int readline(int sd, char *buf, int maxlen){ int n, rch; char ch; for (n=1; n < maxlen; n++) { if ((rch = read(sd, &ch, 1)) == 1) { *buf = ch; buf++; if (ch == ‘\n’) break; } else if (rch == 0) { if (n == 1) return 0; /* EOF, no data read */ else break; /* EOF, some data read */ } else return -1; /* error */ } *buf = ‘\0’; return n;}

More Related