Client server distributed systems
This presentation is the property of its rightful owner.
Sponsored Links
1 / 111

Client/Server Distributed Systems PowerPoint PPT Presentation


  • 129 Views
  • Uploaded on
  • Presentation posted in: General

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

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.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


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

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


1 socket definition

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


2 socket data structures

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


Networked socket data structures

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


Client

  • 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


Socket types

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


3 connection oriented servers

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


Basic client server operation

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()


3 1 tcp serv sock

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.


Initialising a sockaddr in struct

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


Notes

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


Tcp serv sock

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


Client

/* 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


Client

/* 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;}


3 1 1 socket

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


Client

  • 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”


3 1 2 bind

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”


3 1 3 listen

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


Client

  • 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.


4 an iterative server

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


Outline code

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;}


4 0 1 accept

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


Client

  • 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


Client

  • 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


Code fragment

Code Fragment

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


4 0 2 do something

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


Client

  • 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’


4 1 example a daytime server

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.


Day serv c

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


Client

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


Client

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


Running day serv c

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 */


Using day serv

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


4 2 example an echo server

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.


Echo serv c

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


Client

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


Client

if (cdsock < 0) fprintf(stderr, “accept failed\n”); else {echo_upper(cdsock); close(cdsock); } } return 0;}

application specific part

continued


Client

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


Client

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


Client

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;}


Three input termination cases

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.


Running echo serv c

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 */


Using echo serv

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.


4 3 problems with read write

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


Client

  • 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


Client

  • 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


Client

  • 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"


4 3 1 readline

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


Client

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;}


4 3 2 writen

4.3.2. writeN()

  • User-defined function that is guaranteed to write N bytes from a character array.

  • It repeatedly calls write(), and looks at the number returned to determine if write() needs to be called again.


Client

int writeN(int sd, char *buf, int nbytes){ int nleft, nwritten; nleft = nbytes; while (nleft > 0) { nwritten = write(sd, buf, nleft); if (nwritten <= 0) return nwritten; /* error */ nleft -= nwritten; buf += nwritten; } return (nbytes - nleft);}


4 3 3 recoding echo upper

4.3.3. Recoding echo_upper()

void echo_upper(int sd){ char buf[BUFSIZE]; int n; while (((n = readline(sd, buf, sizeof(buf)) != 0) && (!end_input(buf, n))) if (n < 0) fprintf(stderr, “echo read error\n”); else { touppers(buf); if (writeN(sd, buf, n) < 0) fprintf(stderr, “echo write error\n”); }}


4 4 example hangman game

4.4. Example: Hangman Game

  • The server lets the client try to guess a word

    • the word is sent, replaced by ‘-’s

    • the client sends a letter that may be in the word

    • the server updates the guess word, and resends it

  • After 12 incorrect guesses, the client is ‘hanged’ (loses).

  • The server runs on takasila at port 1668.


Hang serv c

hang_serv.c

#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <unistd.h>#include <stdlib.h> /* for random functions */#include <time.h>#define PORT 1668#define BUFSIZE 128#define MAXLIVES 12 /* max guesses */#define NUMWORDS 10 /* no. of words */:

continued


Client

enum game_states {INCOMPLETE, WON, LOST};char *word[] = { “aardvark”, “abacus”, “albatross”, ..., “parallelism”, “zoology” };int tcp_serv_sock(int port);int readline(int sd, char *buf, int maxlen);int writeN(int sd, char *buf,int nbytes);int end_input(char buf[], int len);void play_hangman(int sd);:

continued


Client

int main(){ int rdsock, cdsock, client_len; struct sockaddr_in client; rdsock = tcp_serv_sock(PORT);srand(time(NULL)); /* seed random */ while(1) { client_len = sizeof(client); cdsock = accept(rdsock, (struct sockaddr *)&client,&client_len);:

continued


Client

if (cdsock < 0) fprintf(stderr, “accept failed\n”); else {play_hangman(cdsock); close(cdsock); } } return 0;}

application specific part

continued


Client

void play_hangman(int sd){ char *whole_word, part_word[BUFSIZE], guess[BUFSIZE], outbuf[BUFSIZE]; enum game_states game_state = INCOMPLETE; int lives = MAXLIVES; /* no of lives left */ int i, good_guess, word_length, n; :

continued


Client

/* Pick a word at random from word[] */ whole_word = word[rand()%NUMWORDS]; word_length = strlen(whole_word); for(i=0; i < word_length; i++) part_word[i] = '-'; part_word[i] = '\0'; sprintf(outbuf, " %s %d\n", part_word, lives); writeN(sd, outbuf, strlen(outbuf));:

continued


Client

while (game_state == INCOMPLETE) { /* Get guess letter from player */ if (((n = readline(sd, guess, BUFSIZE)) <= 0) || (end_input(buf, n))) { fprintf(stderr, "readline error\n"); return; } good_guess = 0; for(i=0; i < word_length; i++) if (guess[0] == whole_word[i]) { good_guess = 1; part_word[i] = whole_word[i]; }:

continued


Client

if (!good_guess) lives--; if (strcmp(whole_word, part_word) == 0) game_state = WON; else if (lives == 0) { game_state = LOST; strcpy(part_word, whole_word);

} sprintf(outbuf, " %s %d\n", part_word, lives); writeN(sd, outbuf, strlen(outbuf)); }}


Usage

Usage

  • $ ./hang_serv &/* on takasila */

  • $ telnet takasila 1668 /* on fivedots */Trying 172.30.0.82...Connected to takasila.coe.psu.ac.th.Escape character is ‘^]’ -----------12e ------e----12s ------e--s-12:


5 clients

5. Clients

dealt with by my

get_addr()

Initialise serveraddress details

Create socket with socket()

dealt with by my

open_tcp_sock()

Connect to server’sport with connect()

connectto server

write()

read()


5 1 building the server s address

sin_family

sin_port

sin_addr

sin_zero[8]

5.1. Building the Server’s Address

in the client

addr

AF_INET

htons(host_port)

gethostbyname(host)->h_addr

pad with 0’s

The server is also known as the host.


5 1 1 gethostbyname

5.1.1. gethostbyname()

  • Get details on the host (the server):#include <netdb.h>struct hostent *gethostbyname(char *hostname);

  • Return host details if ok, NULL on error.

e.g. fivedots.coe.psu.ac.th


Struct hostent in netdb h

struct hostent(in netdb.h)

struct hostent { char *h_name; /* official host name */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length;/* address length */ char **h_addr_list;/* array of addresses; ends with NULL */};#define h_addr h_addr_list[0]/* first address in list */


Diagram form

. . . .

Diagram Form

NULL

h_addr_list

hp

addr

addr

h_addr

. . .

hostent struct


5 1 2 code fragment

5.1.2. Code Fragment

struct sockaddr_in addr;struct hostent *hp;:memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(port);if ((hp = gethostbyname(host)) == NULL){ fprintf(stderr, “Unknown addr\n”); exit(1);}memcpy(&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);


5 1 3 bstring h problem

5.1.3. bstring.h Problem

  • Some UNIXs (but not Linux) use bstring.h:

    • memset(&addr, 0, sizeof(addr)); replaced bybzero(&addr, sizeof(addr));

    • memcpy(&addr.sin_addr.s_addr, hp->h_addr,hp->h_length); replaced bybcopy(hp->h_addr, &addr.sin_addr.s_addr,hp->h_length);


5 2 address conversion functions

5.2. Address Conversion Functions

  • Convert a dotted-decimal address in string format (e.g. "192.100.77.3") into an in_addr structure:#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>int inet_aton(const char *addr, struct in_addr *iaddr);

  • Returns non-negative if ok, 0 on error.

"192.100.77.3"

goes here

continued


Networked socket data structures again

Networked Socket Data Structures Again

struct sockaddr_in { short sin_family; /* always AF_INET */ 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;};

  • Details in /usr/include/netinet/in.h


Using inet aton

Using inet_aton()

struct sockaddr_in foo;struct in_addr iaddr;:if (inet_aton("192.100.77.3", &iaddr) != 0) memcpy(&foo.sin_addr, &iaddr, sizeof(iaddr));:


Inet addr

inet_addr()

  • inet_aton() is not supported on some UNIXes (e.g. SunOS), so you must use:

    #include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>unsigned long inet_addr(const char *addr);

    • Returns -1 (INADDR_NONE) on error which can be confused with the long integer for address 255.255.255.255

"192.100.77.3"

goes here


Using inet addr

Using inet_addr()

struct sockaddr_in foo;unsigned long lgaddr;:if ((lgaddr = inet_addr("192.100.77.3"))!= -1) foo.sin_addr.s_addr = lgaddr; :


Inet ntoa

inet_ntoa()

  • Convert in_addr to a dotted-decimal address (in string format):#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>char *inet_ntoa(struct in_addr inaddr);

  • Returns dotted-decimal string if ok, NULL on error.


5 2 1 get addr

5.2.1. get_addr()

  • My function for reading a host string (in dotted-decimal or dotted-name format) and a port number from the command line.

  • If no port number is supplied, the function uses the value in #define PORT

  • get_addr() returns a sockaddr_in struct containing the address details.


Usage1

Usage

processed by get_addr()

the program

using get_addr()

dotted-name or

dotted-decimal

optional port

number

  • $ foobar takasila.coe.psu.ac.th 1667

  • $ foobar takasila

  • $ foobar takasila 1667

  • $ foobar 172.30.0.82


In the foobar c code

In the foobar.c code

int main(int argc, char *argv[]){ : int sd; // socket descriptor struct sockaddr_in netaddr; netaddr = get_addr(argc, argv); sd = open_tcp_sock(netaddr); :


Client

struct sockaddr_in get_addr(int argc, char *argv[]){ struct sockaddr_in addr; unsigned long lgaddr; struct hostent *hp; int port; if ((argc < 2) || (argc > 3)) { fprintf(stderr, "Expect address [port]\n"); exit(1); }:

continued


Client

if (argc == 2) port = PORT; /* default value */ else { port = atoi(argv[2]); if (port < 1024) { fprintf(stderr, "The port number cannot be < 1024\n"); exit(1); } }:

continued


Client

memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); if ((lgaddr = inet_addr(argv[1])) != -1) /* dotted-decimal */ addr.sin_addr.s_addr = lgaddr; else if ((hp = gethostbyname(argv[1])) != NULL) /* lookup name */ memcpy(&addr.sin_addr.s_addr, hp->h_addr, hp->h_length); else { fprintf(stderr, "Unknown address\n"); exit(1); } return addr;}


5 3 open tcp sock

5.3. open_tcp_sock()

  • My function that carries out socket creation and connection in a client.

  • It assumes that the TCP protocol is being used.


Client

Code

int open_tcp_sock(struct sockaddr_in netaddr){ int sd; if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "socket() error\n"); exit(1); } if (connect(sd, (struct sockaddr *)&netaddr, sizeof(netaddr)) < 0) { fprintf(stderr, "Can not connect\n"); exit(1); } return sd;}


Connect

connect()

  • Connect the socket to the server at the specified address:#include <sys/types.h>#include <sys/socket.h>int connect(int sd, struct sockaddr *servaddr, int addrlen);

  • Return 0 if ok, -1 on error.


5 4 example a daytime client

5.4. Example: A Daytime Client

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <unistd.h>:

continued


Client

#define PORT 1666#define LINELEN 128struct sockaddr_in get_addr(int argc, char *argv[]);int open_tcp_sock(struct sockaddr_in netaddr);int readline(int sd, char *buf, int maxlen);:

continued


Client

int main(int argc, char *argv[]){ struct sockaddr_in netaddr; int sd, buflen; char buf[LINELEN]; netaddr = get_addr(argc, argv); sd = open_tcp_sock(netaddr); while ((buflen = readline(sd,buf, LINELEN)) != 0) if (buflen < 0) { fprintf(stderr, “read failed\n”); exit(1); } else fputs(buf, stdout); close(sd); return 0;}


Using day cli

Using day_cli

  • $ gcc -Wall -o day_cli day_cli.c$ ./day_cli takasilaWed May 4 11:27:40 2005$ ./day_cli takasilaWed May 4 11:27:42 2005

  • day_serv must be running at port 1666 on takasila.

executed on

fivedots


5 5 example a hangman client

5.5. Example: A Hangman Client

#include <stdio.h>#include <string.h>: /* same as for day_cli.c */#include <unistd.h>#define PORT 1668#define LINELEN 128struct sockaddr_in get_addr(int argc, char *argv[]);int open_tcp_sock(struct sockaddr_in netaddr);int readline(int sd, char *buf, int maxlen);int writeN(int sd, char *buf, int nbytes);:

continued


Client

int main(int argc, char *argv[]){ struct sockaddr_in netaddr; int sd; char buf[LINELEN]; netaddr = get_addr(argc, argv); sd = open_tcp_sock(netaddr); while (readline(sd, buf, LINELEN) > 0) { // 1 fputs(buf, stdout); // 2 fgets(buf, LINELEN, stdin); // 3 writeN(sd, buf, strlen(buf)); // 4 } return 0;}


Interaction diagram

Interaction Diagram

3) Possible

letter: 'e'

4) 'e'

hang_serv

hang_cli

1) Guess theword: -------

2) ------

on takasila

on fivedots

network


Using hang cli

Using hang_cli

  • $ gcc -Wall -o hang_cli hang_cli.c$ ./hang_cli takasila -----------12e ------e----12s ------e--s-12:

  • hang_serv must be running at port 1668 on takasila.

executed on

fivedots


6 clients of system services

6. Clients of System Services

  • System services include:

    • ftp, Web server, finger, telnet

  • A list of possible services are in /etc/services:

    :ftp21/tcp:finger79/tcpwww80/tcpwww80/udp:


What services are running

What services are running?

  • Most system services are started by inetd.

  • The list of the services it starts are in /etc/inetd.conf:

    :finger stream tcp nowait root/usr/sbin/tcpd /usr/sbin/cfingerd:

takasila does not start finger; calvin does


6 1 a system service address

6.1. A System Service Address

  • We can use getservbyname() to obtain the reserved port number for a given service name (on the client’s machine).

  • This approach assumes that the service will use the same port on its own machine.


6 1 1 build the service address

sin_family

sin_port

sin_addr

sin_zero[8]

6.1.1. Build the Service Address

addr

AF_INET

getservbyname(service)->s_port

gethostbyname(host)->h_addr

pad with 0’s


6 1 2 getservbyname

6.1.2. getservbyname()

  • Lookup service details for a given service name:#include <netdb.h>struct servent *getservbyname(char *servname, char *protname);

  • e.g. getservbyname("finger","tcp");

  • Return service details if ok, NULL on error.


6 1 3 struct servent

6.1.3. struct servent

struct servent { char *s_name; /* service name */ char **s_aliases; /* alias list */ int s_port;/* port number, in network byte order */ char *s_proto; /* protocol to use */}


6 2 get tcp serv addr

6.2. get_tcp_serv_addr()

  • My function which uses the host name (in dotted-decimal or dotted-name string form) and service name to build a sockaddr_in struct for a service.

  • It assumes that the service uses the TCP protocol.

continued


Usage2

Usage

  • $ foobar takasila.coe.psu.ac.th

  • $ foobar takasila

  • $ foobar 172.30.0.82

program using

get_tcp_serv_addr()

dotted-name or

dotted-decimal


In the foobar c code1

In the foobar.c code

int main(int argc, char *argv[]){ : int sd; // socket descriptor struct sockaddr_in netaddr; netaddr = get_tcp_serv_addr(argv[1], "service name"); sd = open_tcp_sock(netaddr); :

dotted name or

dotted decimal


Client

struct sockaddr_in get_tcp_serv_addr(char *host, char *service){ struct sockaddr_in addr; unsigned long lgaddr; struct hostent *hp; struct servent *sp; if ((sp = getservbyname(service, “tcp”)) == NULL) { fprintf(stderr, "Unknown service\n”); exit(1); } :

e.g. "finger"

continued


Client

memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET;addr.sin_port = sp->s_port; if ((lgaddr = inet_addr(host)) != -1) /* dotted-decimal */ addr.sin_addr.s_addr = lgaddr; else if ((hp = gethostbyname(host)) != NULL) /* lookup name */ memcpy(&addr.sin_addr.s_addr, hp->h_addr, hp->h_length); else { fprintf(stderr, "Unknown address\n"); exit(1); } return addr;}


6 3 example finger using telnet

6.3. Example: finger using telnet

  • Using the finger service:

    $ telnet calvin 79Trying 172.30.161.2...Connected to calvin.coe.psu.ac.th.Escape character is '^]'. ad/* many lines of finger information sent back */Connection closed by foreign host.$

executed on

fivedots

you must type at least a return


A finger client

A finger Client

  • finger_cli.c reads the hostname and user login ID from the command line, and then queries “finger” on that host for that login ID.


Finger cli c

finger_cli.c

#include <stdio.h>#include <string.h>:/* same as for day_cli.c */#include <unistd.h>#define LINELEN 128struct sockaddr_in get_tcp_serv_addr(char *host, char *service);int open_tcp_sock(struct sockaddr_in netaddr);int readline(int sd, char *buf, int maxlen);int writeN(int sd, char *buf, int nbytes);:

continued


Client

int main(int argc, char *argv[]){ struct sockaddr_in netaddr; int sd; char buf[LINELEN]; netaddr = get_tcp_serv_addr(argv[1], “finger”); sd = open_tcp_sock(netaddr); sprintf(buf, “%s\n”, argv[2]); writeN(sd, buf, strlen(buf)); // 1 while (readline(sd, buf, LINELEN) > 0) // 2 fputs(buf, stdout); // 3 return 0;}

hostname

login ID


Interaction diagram1

Interaction Diagram

1) "ad"

finger

daemon

finger_cli

2) lines of

output

3) lines

to screen

on fivedots

on calvin

network


Using finger cli

Using finger_cli

$ gcc -Wall -o finger_cli finger_cli.c$ finger_cli calvin ad /* many lines of finger information sent back */$

executed on

fivedots


7 more details

7. More Details

  • UNIX Network Programming, Vol. 1W. Richard StevensPrentice Hall, 1998 (2nd ed.)

    • tough, but the introductory chapters (1-9) are fairly ‘easy’.

  • Brown, chapter 4, is easier.


  • Login