Client server distributed systems
Download
1 / 111

Client - PowerPoint PPT Presentation


  • 181 Views
  • Updated On :

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

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Client' - paxton


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



Socket types
Socket Types require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

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() require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

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 require that sockets be cast into a ‘generic’ socket data type:

  • 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() require that sockets be cast into a ‘generic’ socket data type:

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


/* initialise socket address data struct */ require that sockets be cast into a ‘generic’ socket data type: 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


/* bind socket to address */ require that sockets be cast into a ‘generic’ socket data type: 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() require that sockets be cast into a ‘generic’ socket data type:

  • 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


  • family require that sockets be cast into a ‘generic’ socket data type: 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() require that sockets be cast into a ‘generic’ socket data type:

  • 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() require that sockets be cast into a ‘generic’ socket data type:

  • 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


  • backlog require that sockets be cast into a ‘generic’ socket data type: 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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

#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() require that sockets be cast into a ‘generic’ socket data type:

  • 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


  • accept() require that sockets be cast into a ‘generic’ socket data type: 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


  • peer require that sockets be cast into a ‘generic’ socket data type: 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 require that sockets be cast into a ‘generic’ socket data type:

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() require that sockets be cast into a ‘generic’ socket data type:

  • 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


  • The communication possible with require that sockets be cast into a ‘generic’ socket data type: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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

#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


int main() require that sockets be cast into a ‘generic’ socket data type:{ 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


if (cdsock < 0) require that sockets be cast into a ‘generic’ socket data type: 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 require that sockets be cast into a ‘generic’ socket data type:

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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

#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


int main() require that sockets be cast into a ‘generic’ socket data type:{ 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


if (cdsock < 0) require that sockets be cast into a ‘generic’ socket data type: fprintf(stderr, “accept failed\n”); else {echo_upper(cdsock); close(cdsock); } } return 0;}

application specific part

continued


void echo_upper(int sd) require that sockets be cast into a ‘generic’ socket data type:{ 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


void touppers(char buf[]) require that sockets be cast into a ‘generic’ socket data type:{ int i = 0; while (buf[i] != ‘\n’) { buf[i] = toupper(buf[i]); i++; }}


int end_input(char buf[], int len) require that sockets be cast into a ‘generic’ socket data type:/* 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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

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 require that sockets be cast into a ‘generic’ socket data type:

  • 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() require that sockets be cast into a ‘generic’ socket data type:

  • 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


  • Must call require that sockets be cast into a ‘generic’ socket data type: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


  • One problem: require that sockets be cast into a ‘generic’ socket data type:

    • 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


  • The problems continues: require that sockets be cast into a ‘generic’ socket data type:

    • 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() require that sockets be cast into a ‘generic’ socket data type:

  • 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


int readline(int sd, char *buf, int maxlen) require that sockets be cast into a ‘generic’ socket data type:{ 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() require that sockets be cast into a ‘generic’ socket data type:

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


int writeN(int sd, char *buf, int nbytes) require that sockets be cast into a ‘generic’ socket data type:{ 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() require that sockets be cast into a ‘generic’ socket data type:

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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

#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


enum game_states require that sockets be cast into a ‘generic’ socket data type: {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


int main() require that sockets be cast into a ‘generic’ socket data type:{ 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


if (cdsock < 0) require that sockets be cast into a ‘generic’ socket data type: fprintf(stderr, “accept failed\n”); else {play_hangman(cdsock); close(cdsock); } } return 0;}

application specific part

continued


void play_hangman(int sd) require that sockets be cast into a ‘generic’ socket data type:{ 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


/* Pick a word at random from word[] */ require that sockets be cast into a ‘generic’ socket data type: 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


while (game_state == INCOMPLETE) { require that sockets be cast into a ‘generic’ socket data type: /* 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


if (!good_guess) require that sockets be cast into a ‘generic’ socket data type: 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 require that sockets be cast into a ‘generic’ socket data type:

  • $ ./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 require that sockets be cast into a ‘generic’ socket data type:

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 require that sockets be cast into a ‘generic’ socket data type:

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() require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:(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

. . . . require that sockets be cast into a ‘generic’ socket data type:

Diagram Form

NULL

h_addr_list

hp

addr

addr

h_addr

. . .

hostent struct


5 1 2 code fragment
5.1.2. Code Fragment require that sockets be cast into a ‘generic’ socket data type:

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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

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() require that sockets be cast into a ‘generic’ socket data type:

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() require that sockets be cast into a ‘generic’ socket data type:

  • 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() require that sockets be cast into a ‘generic’ socket data type:

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() require that sockets be cast into a ‘generic’ socket data type:

  • 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() require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

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 require that sockets be cast into a ‘generic’ socket data type:

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


struct sockaddr_in get_addr(int argc, require that sockets be cast into a ‘generic’ socket data type: 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


if (argc == 2) require that sockets be cast into a ‘generic’ socket data type: port = PORT; /* default value */ else { port = atoi(argv[2]); if (port < 1024) { fprintf(stderr, "The port number cannot be < 1024\n"); exit(1); } } :

continued


memset(&addr, 0, sizeof(addr)); require that sockets be cast into a ‘generic’ socket data type: 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() require that sockets be cast into a ‘generic’ socket data type:

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

  • It assumes that the TCP protocol is being used.


Code require that sockets be cast into a ‘generic’ socket data type:

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() require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

#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


#define PORT require that sockets be cast into a ‘generic’ socket data type: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


int main(int argc, char *argv[]) require that sockets be cast into a ‘generic’ socket data type:{ 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 require that sockets be cast into a ‘generic’ socket data type:

  • $ 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 require that sockets be cast into a ‘generic’ socket data type:

#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


int main(int argc, char *argv[]) require that sockets be cast into a ‘generic’ socket data type:{ 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 require that sockets be cast into a ‘generic’ socket data type:

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 require that sockets be cast into a ‘generic’ socket data type:

  • $ 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 require that sockets be cast into a ‘generic’ socket data type:

  • System services include:

    • ftp, Web server, finger, telnet

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

    : ftp 21/tcp : finger 79/tcp www 80/tcp www 80/udp:


What services are running
What services are running? require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

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() require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

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() require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

  • $ 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 require that sockets be cast into a ‘generic’ socket data type:

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


struct sockaddr_in require that sockets be cast into a ‘generic’ socket data type: 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


memset(&addr, 0, sizeof(addr)); require that sockets be cast into a ‘generic’ socket data type: 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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

  • 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 require that sockets be cast into a ‘generic’ socket data type:

#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


int main(int argc, char *argv[]) require that sockets be cast into a ‘generic’ socket data type:{ 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 require that sockets be cast into a ‘generic’ socket data type:

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 require that sockets be cast into a ‘generic’ socket data type:

$ 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 require that sockets be cast into a ‘generic’ socket data type:

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


ad