Network Programming Part II 1 Some Useful UNIX

  • Slides: 106
Download presentation
Network Programming Part II 1

Network Programming Part II 1

Some Useful UNIX Commands • netstat – Print network connections, routing tables, interface statistics,

Some Useful UNIX Commands • netstat – Print network connections, routing tables, interface statistics, masquerade connections, and multicast memberships • dig – DNS lookup utility • route – Show / manipulate the IP routing table • host – DNS lookup utility • ip – TCP/IP interface configuration and routing utility • ifconfig – Configure a network interface or show config. info • arp – Manipulate or display the system ARP cache • tcpdump – dump traffic on a network • whereis – Find a command or file 2

Client-Server Paradigm • Server program – Run 24 hours, 7 days a week listening

Client-Server Paradigm • Server program – Run 24 hours, 7 days a week listening for requests from clients – Process a client’s request according to some agreed upon (or standard) protocol – Serve many clients concurrently or one client at a time – Should be robust and powerful • Client program – Run when a user decides to – Send requests for service to intended server according to some agreed upon (or standard) protocol – Should have a good user interface 3

Client-Server Paradigm (cont’d) • Note: – A computer system can have many server programs

Client-Server Paradigm (cont’d) • Note: – A computer system can have many server programs running and can also be used to run many client programs simultaneously – There is no such distinction that a machine is a server machine or a client machine 4

Server Types Based on Implementation Server Types TCP Based Concurrent Iterative UDP Based Concurrent

Server Types Based on Implementation Server Types TCP Based Concurrent Iterative UDP Based Concurrent Iterative 5

Protocol Families in UNIX Environment • Protocol family PF_UNIX – Designated by an integer

Protocol Families in UNIX Environment • Protocol family PF_UNIX – Designated by an integer constant 1 – Strictly supported on UNIX system • Protocol family PF_INET – Designated by an integer constant 2 – Related to Internet protocols Protocol Families PF_UNIX PF_INET (Used for Internet Programming) 6

Address Families • Address family AF_UNIX – Designated by an integer constant 1 –

Address Families • Address family AF_UNIX – Designated by an integer constant 1 – Strictly used for UNIX hosts • Address family AF_INET – Designated by an integer constant 2 – Related to Internet hosts Address Families AF_UNIX AF_INET (Used for Internet Programming) 7

Socket Abstraction • Used for client server data communication • An application layer abstraction

Socket Abstraction • Used for client server data communication • An application layer abstraction similar to a file descriptor • Hide transport layer details • Is opened in an application program at the beginning • Data can be sent to or received from it • Is closed at the end of use Client Application Create/open socket Initialize/configure socket Communicate data Close socket 8

Socket Abstraction (cont’d) C S L E I R Network E V N E

Socket Abstraction (cont’d) C S L E I R Network E V N E T R 9

Types of Sockets in UNIX (LINUX) system • Stream socket SOCK_STREAM – uses TCP

Types of Sockets in UNIX (LINUX) system • Stream socket SOCK_STREAM – uses TCP as transport protocol – designated by an integer constant 1 • Datagram socket SOCK_DGRAM – uses UDP as transport protocol – designated by an integer constant 2 • Raw socket SOCK_RAW – designated by an integer constant 3 – Useful for sending ICMP messages • Two more types: SOCK_SEQPACKET and SOCK_RDM 10

Socket Types SOCK_STREAM (TCP) SOCK_DGRAM (UDP) SOCK_RAW SOCK_SEQPACKET SOCK_RDM 11

Socket Types SOCK_STREAM (TCP) SOCK_DGRAM (UDP) SOCK_RAW SOCK_SEQPACKET SOCK_RDM 11

Socket Address Structures • Struct sockaddr – holds socket address information for many types

Socket Address Structures • Struct sockaddr – holds socket address information for many types of sockets (not only for AF_NET family) struct sockaddr { u_short sa_family; char sa_data[14]; }; // address family // protocol address – sa_family is AF_INET for an Internet socket address – sa_data contains destination address and port number packed in some format 12

Socket Address Structures (Cont’d) • Struct sockaddr_in – holds socket address information for Internet

Socket Address Structures (Cont’d) • Struct sockaddr_in – holds socket address information for Internet (“in” for Internet) struct sockaddr_in { short int sin_family; u_short sin_port; struct in_addr sin_addr; u_char sin_zero[8]; }; – – // Address family // Port number // Internet address // Same size as struct sockaddr sin_family is AF_INET for Internet sin_port is port number in network byte order sin_addr holds IP address in network byte order (see next slide for detail) sin_zero is needed for padding. It makes sockaddr_in to type cast to sock_addr and vice versa 13

Socket Address Structures (Cont’d) • Struct in_addr – It contains IP address in network

Socket Address Structures (Cont’d) • Struct in_addr – It contains IP address in network byte order (NBO) struct in_addr { u_long s_addr; // 32 bit IP address in network byte order }; 14

Illustration of Address Structures NBO: Network Byte Order sockaddr_in sa_family (2 bytes) sin_family (2

Illustration of Address Structures NBO: Network Byte Order sockaddr_in sa_family (2 bytes) sin_family (2 bytes, NBO) sa_data NBO sin_port (2 bytes, NBO) (14 bytes) sin_addr (4 bytes, NBO) in_addr sin_zero (8 bytes) (16 bytes total) 15

Memory Copy and Initialization Functions • Network programming frequently involves coping one memory area

Memory Copy and Initialization Functions • Network programming frequently involves coping one memory area to some other memory area – bcopy() or memcpy() function can be used for the purpose • Network programming also involves initializing some memory area with binary zeros – bzero() or memset() can be used for this 16

bzero() Function Memory • Writes zeros to a byte string #include <string. h> void

bzero() Function Memory • Writes zeros to a byte string #include <string. h> void bzero(void *s, size_t n); • Sets the first n bytes of the byte string s to zero (binary 0000). ? ? ? ? (before) ? ? ? ? bzero() 00000000 (after) 17

bcopy() Function • Copies byte strings #include <string. h> void bcopy (const void *src,

bcopy() Function • Copies byte strings #include <string. h> void bcopy (const void *src, void *dest, size_t n); • Copies first n bytes of the source string src to destination string dest. 0 B 10100 A Source 0 C 11000 B 001 A 2001 1001000 F bcopy() 0 B 10100 A 0 C 11000 B Destination 001 A 2001 1001000 F 18

Example with bzero() and bcopy() /* use of bzero() and bcopy() functions */ #include

Example with bzero() and bcopy() /* use of bzero() and bcopy() functions */ #include <stdio. h> #include <string. h> Person John = {502085332, "John Foster", 30}; numbytes = sizeof(Person); dest. Ptr = (char *) malloc(numbytes); src. Ptr = (char *) &John; int main(void) { char *src. Ptr, *dest. Ptr; int numbytes; typedef struct { long int ssn; char name[41]; unsigned short age; } Person; bzero(dest. Ptr, numbytes); bcopy(src. Ptr, dest. Ptr, numbytes); Person *personptr; personptr = (Person *) dest. Ptr; printf("%dn", personptr >ssn); printf("%sn", personptr >name); printf("%dn", personptr >age); return 0; } 19

Illustration src. Ptr 502085332 (long int) “John Foster” (string) 30 (short int) bcopy() dest.

Illustration src. Ptr 502085332 (long int) “John Foster” (string) 30 (short int) bcopy() dest. Ptr (personptr) 502085332 (long int) “John Foster” (string) 30 (short int) Note: char * dest. Ptr is typecast to Person * personptr to access members in the data structure 20

socket() Function • Returns a socket descriptor (an integer), or 1 on error #include

socket() Function • Returns a socket descriptor (an integer), or 1 on error #include <sys/types. h> #include <sys/socket. h> int socket(int domain, int type, int protocol); – domain is PF_INET for Internet (protocol family) – type is SOCK_STREAM and protocol is 0 for TCP – type is SOCK_DGRAM and protocol is 0 for UDP 21

connect() Function • Initializes and initiates a connection on a socket to communicate with

connect() Function • Initializes and initiates a connection on a socket to communicate with a destination host #include <sys/types. h> #include <sys/socket. h> int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen); – sockfd is a socket descriptor that refers to a socket – serv_addr is for destination host address structure (server) – addrlen is length of server (destination) address structure 22

read() Function • Reads bytes from a socket (or a file descriptor). Technically, it

read() Function • Reads bytes from a socket (or a file descriptor). Technically, it transfers bytes (if available) from transport layer area to application program area int read(sock_fd, char* buffer, int len); • Returns number of bytes read from socket sock_fd • Bytes are saved in buffer • len is the largest number of bytes a programmer would like to read from socket and save in buffer. len must not exceed the size of buffer. 23

Example: Day time Service • Day time server runs on port 13 • When

Example: Day time Service • Day time server runs on port 13 • When a client connects to a TCP based day time server, it returns information on day and time and then closes the connection. • Atomic timer server – time a. timefreq. bldrdoc. gov – IP addr: 132. 163. 4. 101 – National Institute of Standards and Technology, Boulder, Colorado Listen Accept connection Send day time info Close connection 24

Example: Daytime Client Program // Daytime client // Protocol: TCP #include #include <sys/socket. h>

Example: Daytime Client Program // Daytime client // Protocol: TCP #include #include <sys/socket. h> <stdio. h> <string. h> <sys/types. h> <netinet/in. h> <arpa/inet. h> <unistd. h> <stdlib. h> int main(void) { // create socket int sock; sock = socket(PF_INET, SOCK_STREAM, 0); // 0, tcp by default if(sock < 0) { printf("Failed to create a socketn"); exit(1); } 25

Daytime Client (cont’d) // initialize remote host address structure struct sockaddr_in sin; bzero((char *)

Daytime Client (cont’d) // initialize remote host address structure struct sockaddr_in sin; bzero((char *) &sin, sizeof(sin)); sin_family = AF_INET; // set to internet address type sin_port = htons(13); // set to daytime port number 13 // Set IP address for time-a. timefreq. bldrdoc. gov sin_addr. s_addr = inet_addr("132. 163. 4. 101"); // Connect to remote host using socket and address structure int retcode; retcode = connect(sock, (struct sockaddr *) &sin, sizeof(sin)); if(retcode < 0){ printf("Failed to connect with the hostn"); exit(2); } // Get and print day-time info int bytesread; char buffer[200]; bytesread = read(sock, buffer, sizeof(buffer)-1); buffer[bytesread] = ''; // ensures null terminated printf("%sn", buffer); close(sock); } 26

Flow Diagram of Daytime Client Program Open Socket Initialize remote host address structure with

Flow Diagram of Daytime Client Program Open Socket Initialize remote host address structure with port no, IP address, etc. Establish connection Read and print daytime info. Close socket 27

Remarks • Our daytime client program is a very simple, bare bone client application

Remarks • Our daytime client program is a very simple, bare bone client application – It is a TCP based client program – It does not do any DNS look up to obtain the IP address of the daytime server – IP address of the server is embedded in the program – Port number is hard coded in the program – It does not send any data to the daytime server – It only receives data • A somewhat different daytime client is given next 28

Daytime client, Example 2 // Daytime client 2 // Protocol: TCP #include <sys/socket. h>

Daytime client, Example 2 // Daytime client 2 // Protocol: TCP #include <sys/socket. h> #include <stdio. h> #include <string. h> #include <sys/types. h> #include <netinet/in. h> #include <arpa/inet. h> #include <unistd. h> #include <stdlib. h> #include <netdb. h> char host[] = "time-a. timefreq. bldrdoc. gov"; char service[] = "daytime"; char protocol[] = "tcp"; int main(void) { // create socket int sock; struct protoent *proto. Ptr; proto. Ptr = getprotobyname(protocol); if (proto. Ptr == NULL) { printf("Failed to map protocol name to numbern"); exit(1); } 29

Example 2 (Cont’d) sock = socket(PF_INET, SOCK_STREAM, proto. Ptr->p_proto); if(sock < 0) { printf("Failed

Example 2 (Cont’d) sock = socket(PF_INET, SOCK_STREAM, proto. Ptr->p_proto); if(sock < 0) { printf("Failed to create a socketn"); exit(1); } // Initialize remote host address structure struct sockaddr_in sin; bzero((char *) &sin, sizeof(sin)); // Get port number for the service struct servent * serv. Ptr; serv. Ptr = getservbyname(service, protocol); if (serv. Ptr == NULL) { printf("No entry found for the servicen"); exit(1); } sin_port = serv. Ptr->s_port; // set to daytime port number 30

Example 2 (cont’d) // Get IP address for time-a. timefreq. bldrdoc. gov struct hostent

Example 2 (cont’d) // Get IP address for time-a. timefreq. bldrdoc. gov struct hostent * host. Ptr; host. Ptr = gethostbyname(host); if (host. Ptr == NULL) { printf("Failed to resolve host namen"); exit(2); } bcopy(host. Ptr->h_addr, (char *) &sin. sin_addr, host. Ptr->h_length); sin_family = host. Ptr->h_addrtype; // usually AF_INET int retcode; retcode = connect(sock, (struct sockaddr *) &sin, sizeof(sin)); if(retcode < 0) { printf("Failed to connect with the hostn"); exit(2); } 31

Example 2 (cont’d) // Get daytime info. int bytesread; char buffer[200]; bytesread = read(sock,

Example 2 (cont’d) // Get daytime info. int bytesread; char buffer[200]; bytesread = read(sock, buffer, sizeof(buffer)-1); buffer[bytesread] = ''; // ensures null terminated printf("%sn", buffer); close(sock); return 0; } 32

Remarks • This program – Does DNS lookup to obtain the IP address of

Remarks • This program – Does DNS lookup to obtain the IP address of the server – Finds the protocol number for TCP protocol and accordingly opens a socket for communication – Finds the port number for daytime service and uses it to initialize remote host address structure 33

Monitoring or Detecting Available Services on a Remote System • A server program runs

Monitoring or Detecting Available Services on a Remote System • A server program runs on a port • A TCP based server program – Runs in listening mode waiting to receive connection request – Accepts connection from a client • A successful connection to a port on a remote system by a client is an indication of the presence of a service on the system 34

Service Monitoring or Port Scanning //Service Monitor or Port scanner // Protocol: TCP #include

Service Monitoring or Port Scanning //Service Monitor or Port scanner // Protocol: TCP #include <sys/socket. h> #include <stdio. h> #include <string. h> #include <sys/types. h> #include <netinet/in. h> #include <arpa/inet. h> #include <unistd. h> #include <stdlib. h> #include <netdb. h> char host[] = "conductor. tamucc. edu"; int main(void) { int sock; int retcode; struct sockaddr_in sin; Caution: Don’t try it on an unauthorized system // Get IP Address struct hostent *host. Addr; host. Addr = gethostbyname(host); if (host. Addr == NULL){ printf("Failed to resolve host namen"); exit(1); } 35

Service Monitor or Port Scanner (cont’d) // scan port from 1 to 1000 int

Service Monitor or Port Scanner (cont’d) // scan port from 1 to 1000 int portno; for (portno = 1; portno < 1001; portno ++) { sock = socket(PF_INET, SOCK_STREAM, 0); // 0, tcp by default if(sock < 0) { printf("Failed to create a socketn"); exit(1); } // initialize remote host address structure bzero((char *) &sin, sizeof(sin)); bcopy(host. Addr->h_addr, (char *) &sin. sin_addr, host. Addr->h_length); sin_family = AF_INET; // set to internet address type sin_port = htons(portno); // set to port number to i retcode = connect(sock, (struct sockaddr *) &sin, sizeof(sin)); if(retcode == 0) // connection successful { printf("Service found at port: %d n", portno); close (sock); } } return 0; } Desclaimer: I’m not responsible if you try this program on some unauthorized site – Dr. Kar 36

Server Program • An network application program that provides a specific service to clients

Server Program • An network application program that provides a specific service to clients • Examples: http server, ftp server, telnet server, e mail server, etc. • A server always remains online to serve any client requesting for service 37

TCP Servers • We will call connection oriented servers as TCP servers • A

TCP Servers • We will call connection oriented servers as TCP servers • A TCP server socket always remains open and listens to its port for any connection request from a client • It accepts a connection by opening a separate socket (serving socket) for communication with a client. In case of iterative server, only one such socket is opened. In case of concurrent server, multiple such sockets may remain open, one of each client request. • It closes the socket when done with the client. • Note: Listening or server socket always remains open. 38

An Iterative, TCP-Based Server Setup address structure with its own IP address, own port

An Iterative, TCP-Based Server Setup address structure with its own IP address, own port number, etc Open a socket for listening (sock. Listen) Bind sock. Listen with address structure and set it to listen Accept whenever a connection request arrives from a client and create a new socket (sock. Accept) Communicate or exchange data with the client via sock. Accept Close sock. Accept 39

bind() Function • Specifies a local IP address and protocol port number for a

bind() Function • Specifies a local IP address and protocol port number for a socket (or links a socket to the address structure of the local machine) • Primarily used by servers to specify a well known port #include <sys/socket. h> int bind(int socket, struct sockaddr * serv_addr, int addr_len); • Returns – 0 if successful – 1 if unsuccessful 40

listen() Function #include <sys/socket. h> int listen(int s, int backlog); • Sets a socket

listen() Function #include <sys/socket. h> int listen(int s, int backlog); • Sets a socket to listening mode to receive connection requests from clients • Only applicable for sockets of type SOCK_STREAM or SOCK_SEQPACKET • backlog parameter defines the maximum length of the queue of pending connections • s is the socket number 41

accept() Function • Accepts a connection request and returns a separate socket for communication

accept() Function • Accepts a connection request and returns a separate socket for communication with the client #include <sys/types. h> #include <sys/socket. h> int accept(int socket, struct sockaddr *addr, socklen_t *addrlen); • addr is a pointer to a sockaddr structure to be filled in with address of the connecting entity (i. e. client) • addrlen argument is a value result parameter – Used to pass the size of the structure pointed by addr; – on return, it contains actual length (in bytes) of the address returned. 42

Example: An Iterative TCP Server // Example #include #include of an iterative server <stdio.

Example: An Iterative TCP Server // Example #include #include of an iterative server <stdio. h> <sys/types. h> <sys/socket. h> <netinet/in. h> <netdb. h> <stdlib. h> <string. h> <unistd. h> const int SERVER_PORT = 8888; const int Q_LEN = 5; // number of waiting clients int { main(void) struct sockaddr_in serv_sin; struct sockaddr_in cli_sin; char buffer[500]; int sock. Listen; int sock. Accept; unsigned int addr. Len; // or socklen_t addr. Len int length; 43

Example (Cont’d) // Setup address structure bzero((char *) &serv_sin, sizeof(serv_sin)); serv_sin. sin_family = AF_INET;

Example (Cont’d) // Setup address structure bzero((char *) &serv_sin, sizeof(serv_sin)); serv_sin. sin_family = AF_INET; serv_sin. sin_addr. s_addr = INADDR_ANY; serv_sin. sin_port = htons(SERVER_PORT); // Setup listening socket sock. Listen = socket(PF_INET, SOCK_STREAM, 0); if (sock. Listen < 0) { printf("Failed to create listening socketn"); exit(1); } 44

Example(cont’d) if (bind(sock. Listen, (struct sockaddr *) &serv_sin, sizeof(serv_sin)) < 0) { printf("Failed to

Example(cont’d) if (bind(sock. Listen, (struct sockaddr *) &serv_sin, sizeof(serv_sin)) < 0) { printf("Failed to bind listening socket to address n"); exit(1); } if (listen(sock. Listen, Q_LEN) < 0) { printf("Failed to listenn"); exit(1); } addr. Len = sizeof(cli_sin); 45

Example (cont’d) // Wait for connection requests while (1){ sock. Accept = accept(sock. Listen,

Example (cont’d) // Wait for connection requests while (1){ sock. Accept = accept(sock. Listen, (struct sockaddr *) &cli_sin, &addr. Len); if (sock. Accept < 0){ printf("Failed to accept connectionn"); exit(1); } while (sock. Accept > 0) { length = recv (sock. Accept, buffer, sizeof(buffer), 0); if(length > 0){ int count; for(count = 0; count < length; ++ count) printf("%cn", buffer[count]); // Display client's msg send(sock. Accept, buffer, length, 0); // Echo msg if(buffer[0]=='Q') // Quit communication with client break; } } close(sock. Accept); } return 0; } 46

Constant INADDR_ANY • A host can have multiple IP addresses • INADDR_ANY specifies a

Constant INADDR_ANY • A host can have multiple IP addresses • INADDR_ANY specifies a wildcard IP address that matches any of the host’s addresses • Will allow a single server accept incoming communication addressed to any of its IP addresses 47

Obtaining Client’s Information in a Server Program • When a connection request arrives from

Obtaining Client’s Information in a Server Program • When a connection request arrives from a client, the server also gets address information about the client • Client’s IP address, port number, etc are passed in an address structure • You may use getpeername() function to retrieve such information 48

getpeername() Function • Gets name of connected peer #include <sys/socket. h> int getpeername(int s,

getpeername() Function • Gets name of connected peer #include <sys/socket. h> int getpeername(int s, struct sockaddr *name, socklen_t *namelen); • Returns the address info of the peer connected to socket s. • Before call, name lenparameter points to the amount of space in the addresses structure pointed by name. On return, it points to the actual size of the address structure returned (in bytes). • RETURN VALUE – On success, zero is returned. – On error, 1 is returned. 49

Example 2: Iterative server // Example client's #include #include #include of an iterative server

Example 2: Iterative server // Example client's #include #include #include of an iterative server that gathers info <stdio. h> <sys/types. h> <sys/socket. h> <netinet/in. h> <netdb. h> <stdlib. h> <string. h> <unistd. h> <arpa/inet. h> const int SERVER_PORT = 8888; const int Q_LEN = 5; // number of waiting clients 50

Example 2 (cont’d) int main(void) { struct sockaddr_in serv_sin; char buffer[500]; int sock. Listen;

Example 2 (cont’d) int main(void) { struct sockaddr_in serv_sin; char buffer[500]; int sock. Listen; int sock. Accept; struct sockaddr_in cli_sin; unsigned int addr. Len; // or socklen_t addr. Len int length; // Setup address structure bzero((char *) &serv_sin, sizeof(serv_sin)); serv_sin. sin_family = AF_INET; serv_sin. sin_addr. s_addr = INADDR_ANY; serv_sin. sin_port = htons(SERVER_PORT); 51

Example 2 (cont’d) // Setup listening socket sock. Listen = socket(PF_INET, SOCK_STREAM, 0); if

Example 2 (cont’d) // Setup listening socket sock. Listen = socket(PF_INET, SOCK_STREAM, 0); if (sock. Listen < 0) { printf("Failed to create listening socketn"); exit(1); } if (bind(sock. Listen, (struct sockaddr *) &serv_sin, sizeof(serv_sin)) < 0) { printf("Failed to bind listening socket to addressn"); exit(1); } if (listen(sock. Listen, Q_LEN) < 0) { printf("Failed to listenn"); exit(1); } 52

Example 2 (cont’d) addr. Len = sizeof(cli_sin); // Wait for connection requests while (1)

Example 2 (cont’d) addr. Len = sizeof(cli_sin); // Wait for connection requests while (1) { sock. Accept = accept(sock. Listen, (struct sockaddr *) &cli_sin, &addr. Len); if (sock. Accept < 0) { printf("Failed to accept connectionn"); exit(1); } // Obtain information about the client if(getpeername(sock. Accept, (struct sockaddr *) &cli_sin, &addr. Len) < 0){ printf("Failed to get name and address of clientn"); exit(1); } // Display information printf("Client IP Address: %sn", inet_ntoa(cli_sin. sin_addr)); printf("Client Port: %dn", ntohs(cli_sin. sin_port)); close(sock. Accept); } return 0; } 53

Adv. and Disadv. of Iterative Servers • Some advantages – Simple to implement –

Adv. and Disadv. of Iterative Servers • Some advantages – Simple to implement – Only allocate resources to communicate with one client at a time • Some Disadvantages – While one client is being served , others remain in waiting state (even refused). Can cause long delays. – Exchange of messages among a group of clients served by the server is not possible at all 54

Concurrent TCP Servers • Avoid long delays • Allow communication with many clients to

Concurrent TCP Servers • Avoid long delays • Allow communication with many clients to proceed simultaneously • Better observed response from a client’s point of view • Many possible implementations – One possible implementation is to create a separate process for each communication using UNIX system function fork() 55

Example: Concurrent TCP server // Example of a concurrent server // A child process

Example: Concurrent TCP server // Example of a concurrent server // A child process is created to handle // communications with a client #include <iostream. h> #include <sys/types. h> #include <sys/socket. h> #include <netinet/in. h> #include <netdb. h> #include <stdlib. h> #include <string. h> #include <unistd. h> #include <wait. h> const int SERVER_PORT = 8888; const int Q_LEN = 5; // number of waiting clients void do. Echo(int); 56

void main(void) { struct sockaddr_in serv_sin; struct sockaddr_in cli_sin; int sock. Listen; int sock.

void main(void) { struct sockaddr_in serv_sin; struct sockaddr_in cli_sin; int sock. Listen; int sock. Accept; unsigned int addr. Len; // or socklen_t addr. Len int length; int process. ID; // Setup address structure bzero((char *) &serv_sin, sizeof(serv_sin)); serv_sin. sin_family = AF_INET; serv_sin. sin_addr. s_addr = INADDR_ANY; serv_sin. sin_port = htons(SERVER_PORT); // Setup listening socket sock. Listen = socket(PF_INET, SOCK_STREAM, 0); if (sock. Listen < 0) { cout << "Failed to create listening (server) socket" << endl; exit(1); } 57

if (bind(sock. Listen, (struct sockaddr *) &serv_sin, sizeof(serv_sin)) < 0) { cout <<" Failed

if (bind(sock. Listen, (struct sockaddr *) &serv_sin, sizeof(serv_sin)) < 0) { cout <<" Failed to bind listening socket to address "<<endl; exit(1); } if (listen(sock. Listen, Q_LEN) < 0) { cout << "Failed to listen" << endl; exit(1); } addr. Len = sizeof(cli_sin); 58

// Wait for connection requests while (1) { sock. Accept = accept(sock. Listen, (struct

// Wait for connection requests while (1) { sock. Accept = accept(sock. Listen, (struct sockaddr *) &cli_sin, &addr. Len); if (sock. Accept < 0) { cout << "Failed to accept connection" << endl; exit(1); } cout << "Starting a process" << endl; process. ID = fork(); if (process. ID < 0) { cout <<"Failed to create a process"<<endl; exit(1); } if (process. ID == 0) // Child process { close(sock. Listen); do. Echo(sock. Accept); close(sock. Accept); exit(0); } close(sock. Accept); // Parent process wait 3(NULL, WNOHANG, NULL); // get rid of zombies // freeup resources; } } 59

void do. Echo(int sock. Client) { int length; char buffer[500]; while (1) { length

void do. Echo(int sock. Client) { int length; char buffer[500]; while (1) { length = recv (sock. Client, buffer, sizeof(buffer), 0); if(length > 0) { //for(int count = 0; count < length; ++ count) // cout << buffer[count]; // Display client's message if(buffer[0]=='Q') // Quit break; if(send(sock. Client, buffer, length, 0) < 0) // Echo { cout << "Failed to send" << endl; break; } } 60

Function fork() • Creates a child process that differs from the parent process only

Function fork() • Creates a child process that differs from the parent process only in its PID and PPID • SYNOPSIS #include <sys/types. h> #include <unistd. h> pid_t fork(void); • On success, the PID of the child process is returned in the parent's thread of execution, and a 0 is returned in the child's thread of execution. On failure, a 1 will be returned in the parent's context, no child process will be created. 61

Function wait 3() Suspends execution of the current process until a child has exited,

Function wait 3() Suspends execution of the current process until a child has exited, (or until a signal is delivered whose action is to terminate the current process or to call a signal handling function). If a child has already exited by the time of the call (a so called "zombie" process), the function returns immediately. Any system resources used by the child are freed. • SYNOPSIS #include <sys/types. h> #include <sys/wait. h> pid_t wait 3(int *status, int options, struct rusage *rusage) Note: Check Unix manual for more details. Use the command man wait 3 62

UDP Servers • Server applications designed to run on UDP protocol provide connectionless service

UDP Servers • Server applications designed to run on UDP protocol provide connectionless service • No listening socket required in implementing a connectionless server • No separate socket required to serve a client’s request • Server program processes each request independent of any other requests • No connection establishment/tear down phase 63

UDP Server Example: Echo Server #include <sys/types. h> #include <sys/socket. h> #include <netinet/in. h>

UDP Server Example: Echo Server #include <sys/types. h> #include <sys/socket. h> #include <netinet/in. h> #include <stdio. h> #include <stdlib. h> #include <string. h> int main() { int retcode; int sock; struct sockaddr_in serv. Addr; struct sockaddr_in client. Addr; char buffer[500]; unsigned int length; sock = socket(PF_INET, SOCK_DGRAM, 0); if (sock < 0) { printf("Failed to create a socketn"); exit(1); } 64

Example (cont’d) // To reuse the same port again and again // (good for

Example (cont’d) // To reuse the same port again and again // (good for testing purpose) int i = 1; retcode = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof (i)); if (retcode < 0) { printf("Failed to set socket options for reusen"); exit(1); } length = sizeof(serv. Addr); bzero((char *) &serv. Addr, length); serv. Addr. sin_family = AF_INET; serv. Addr. sin_addr. s_addr = htonl(INADDR_ANY); serv. Addr. sin_port = htons(8888); retcode = bind(sock, (struct sockaddr*)&serv. Addr, length); if (retcode < 0) { printf("Failed to bindn"); exit(1); } 65

Example (cont’d) int bytereceived; // receive and send datagrams in a loop while (1)

Example (cont’d) int bytereceived; // receive and send datagrams in a loop while (1) { bytereceived = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *) &client. Addr, &length); if (bytereceived < 1) { printf("Failed to receive any messagen"); exit(1); } buffer[bytereceived] = ''; // convert to upper case and send message back int count; for(count = 0; buffer[count] != ''; ++count) if(buffer[count] >= 'a' && buffer[count] <= 'z') buffer[count] = buffer[count] -('a' - 'A'); sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr *) &client. Addr, sizeof(client. Addr)); } return 0; } 66

Function setsockopt() • Sets and manipulate the options associated with a socket. There are

Function setsockopt() • Sets and manipulate the options associated with a socket. There are many options that can be set at many protocol level, including socket level #include <sys/types. h> #include <sys/socket. h> int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); • To manipulate options at the socket level, level is specified as SOL_SOCKET • The parameters optval and optlen are used to access option values for setsockopt • SO_REUSEADDR is used for optname to allow reuse of the same port. 67

Function recvfrom() • Receives a message from a remote host through a socket #include

Function recvfrom() • Receives a message from a remote host through a socket #include <sys/types. h> #include <sys/socket. h> int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); • May be used to receive data on a socket whether or not it is connection oriented • If from is not NULL, and the socket is not connection oriented, the source address of the message is filled in. • Argument fromlen is a value result parameter, initialized to the size of buffer associated with from, and modified on return to indicate actual size of the address stored there. 68

Function sendto() • Sends a message from a socket to a socket #include <sys/types.

Function sendto() • Sends a message from a socket to a socket #include <sys/types. h> #include <sys/socket. h> int sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); • May be used for connection oriented socket. • Target address is given by to with tolen specifying its size. • Length of message is given by len. If message is too long to pass atomically through underlying protocol, error EMSGSIZE is returned, and the message is not transmitted. 69

UDP Client • • Uses UDP as the underlying transport protocol Very similar to

UDP Client • • Uses UDP as the underlying transport protocol Very similar to a UDP server in structure One difference: it does not run in an endless loop It does not need to run on a particular port 70

UDP Client Example // UDP Client for an UDP Echo Server #include <stdio. h>

UDP Client Example // UDP Client for an UDP Echo Server #include <stdio. h> #include <sys/types. h> #include <sys/socket. h> #include <netinet/in. h> #include <arpa/inet. h> #include <netdb. h> #include <string. h> #include <stdlib. h> int main(void) { struct sockaddr_in serv. Addr; unsigned int addrlen; int sock; struct hostent *host. Ptr; char buffer[1000]; 71

Example (cont’d) int read. Bytes; int retcode; sock = socket(PF_INET, SOCK_DGRAM, 0); if (sock

Example (cont’d) int read. Bytes; int retcode; sock = socket(PF_INET, SOCK_DGRAM, 0); if (sock < 0){ printf("Failed to create a socketn"); exit(1); } host. Ptr = gethostbyname("penguin. tamucc. edu"); if (host. Ptr == NULL){ printf("Failed to find host infon"); exit(1); } bzero((char *) &serv. Addr, sizeof(serv. Addr)); serv. Addr. sin_family = AF_INET; bcopy(host. Ptr->h_addr, (char *) &serv. Addr. sin_addr, host. Ptr->h_length); serv. Addr. sin_port = htons(8888); addrlen = sizeof(serv. Addr); 72

Example (cont’d) // Without bind() and connect(), we need to use // sendto() and

Example (cont’d) // Without bind() and connect(), we need to use // sendto() and recvfrom() for datagram exchanges // we cannot use write() and read() since they do not // have any address parameter char message[] = "Hello World"; if (sendto(sock, message, strlen(message), 0, (struct sockaddr*) &serv. Addr, addrlen) < 0) { printf("Failed to send messagen"); exit(1); } printf("Sent: %sn", message); read. Bytes = recvfrom(sock, buffer, 999, 0, (struct sockaddr*) host. Ptr, &addrlen); 73

Example (cont’d) if (read. Bytes < 0) { printf("Failed to receive message backn"); exit(1);

Example (cont’d) if (read. Bytes < 0) { printf("Failed to receive message backn"); exit(1); } buffer[read. Bytes] = ''; printf("Received: %sn", buffer); return 0; } 74

Some Useful UNIX Functions and Structures 75

Some Useful UNIX Functions and Structures 75

Elapsed Time • In a server or client program, we may need to measure

Elapsed Time • In a server or client program, we may need to measure the elapsed time in a communication • Example: – File transfer time – Roundtrip time or response time – Session time Record begin_time Do communications & computations Record end_time Compute elapsed time as: end_time – begin_time 76

Example Program to Measure Elapsed Time // How to measure elapsed time #include <stdio.

Example Program to Measure Elapsed Time // How to measure elapsed time #include <stdio. h> #include <sys/time. h> #include <stdlib. h> int main(void) { timeval begintime; timeval endtime; if(gettimeofday(&begintime, NULL) < 0) { printf("Failed to get time of day n“); exit(1); } // Spend some time for ( int i = 0; i < 200000; ++i); 77

Example Program(cont’d) if(gettimeofday(&endtime, NULL) < 0) { printf("Failed to get time of day n“);

Example Program(cont’d) if(gettimeofday(&endtime, NULL) < 0) { printf("Failed to get time of day n“); exit(1); } long microseconds; microseconds = endtime. tv_sec * 1 e 6 + endtime. tv_usec - (begintime. tv_sec * 1 e 6 + begintime. tv_usec); printf("Elapsed time = %d microsecondsn“, microseconds); return 0; } 78

Structure timeval • Specified in /usr/include/sys/time. h: struct timeval { long tv_sec; long tv_usec;

Structure timeval • Specified in /usr/include/sys/time. h: struct timeval { long tv_sec; long tv_usec; }; /* seconds */ /* microseconds */ timeval structure: tv_sec (32 bits) tv_usec (32 bits) 79

Function gettimeofday() • Gives the number of seconds and microseconds since the Epoch (00:

Function gettimeofday() • Gives the number of seconds and microseconds since the Epoch (00: 00 UTC, January 1, 1970) #include <sys/time. h> int gettimeofday(struct timeval *tv, struct timezone *tz); • tz is a timezone : struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; • If either tv or tz is null, the corresponding structure is not set or returned 80

Implementing Timeout in a Program • Internet is an unreliable environment for communications •

Implementing Timeout in a Program • Internet is an unreliable environment for communications • Some client or server may not receive response from its peer within some expected time due some unexpected problem • Examples: – Client or server can crash while communicating – Communications may be filtered out by some firewall – Physical node or link failure can occur • Timeout should be implemented to terminate a program (Otherwise, your program may wait forever expecting a response from peer) 81

Timeout With alarm() Function // Time out with alarm() function // Operates in seconds

Timeout With alarm() Function // Time out with alarm() function // Operates in seconds #include <signal. h> #include <stdio. h> #include <unistd. h> void handle(int); int main(void) { signal(SIGALRM, handle); alarm(5); // Raise signal after 5 sec pause(); printf("Good byen"); return 0; } void handle(int signum) { printf("Alarm worksn"); return; } 82

Function alarm() • Sets an alarm clock for delivery of a signal #include <unistd.

Function alarm() • Sets an alarm clock for delivery of a signal #include <unistd. h> unsigned int alarm(unsigned int seconds); • Arranges for a SIGALRM signal to be delivered to the process in seconds. If seconds is zero, no new alarm is scheduled. In any event any previously set alarm is cancelled. • Returns the number of seconds remaining until any previously scheduled alarm was due to be delivered, or zero if there was no previously scheduled alarm. 83

Function signal() #include <signal. h> void (*signal(int signum, void (*sighandler)(int)))(int); • Installs a new

Function signal() #include <signal. h> void (*signal(int signum, void (*sighandler)(int)))(int); • Installs a new signal handler for the signal with number signum. The signal handler is set to sighandler which may be user specified function, or either SIG_IGN or SIG_DFL. • SIG_IGN: signal is ignored. • SIG_DFL: default action associated to signal occurs • function sighandler: sighandler is called with argument signum. 84

Limitation of alarm() Function • Minimum value of timeout is one second which is

Limitation of alarm() Function • Minimum value of timeout is one second which is indeed very large for data communications. • Alternatively, you may use select() function which can be used to set timeout to microseconds 85

Pause or Timeout with select() function // It can be set to microsecond level

Pause or Timeout with select() function // It can be set to microsecond level #include <unistd. h> #include <sys/types. h> #include <stdio. h> int main(void){ struct timeval T; T. tv_sec = 5; T. tv_usec = 10000; select(0, NULL, &T); //pause printf("Waited specified amount of time. n"); printf("Time left: %d seconds and %d microsecondsn", T. tv_sec, T. tv_usec); return 0; } 86

Structure fd_set • Used to declare a set of file descriptors for select() function

Structure fd_set • Used to declare a set of file descriptors for select() function • An fd_set is a bit array • A set of descriptors – Read file descriptors – Write file descriptors – Exceptions • Note that sockets are also file descriptors • All file descriptors are integers • Function select() uses sets of descriptors as arguments 87

Function select() #include <sys/time. h> #include <sys/types. h> #include <unistd. h> int select(int nfds,

Function select() #include <sys/time. h> #include <sys/types. h> #include <unistd. h> int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); • A powerful function used to watch/monitor any change of status of any file descriptor for a given timeout period • Good for concurrent read/write operations • Check this link for details: – http: //www. gnu. org/manual/glibc 2. 2. 5/html_node/Waiting for I O. html 88

Function select() (con’td) • Waits for a number of file descriptors to change status.

Function select() (con’td) • Waits for a number of file descriptors to change status. • Uses a timeout • Three independent sets of file descriptors readfds, writefds, and exceptfds are watched. – Descriptors in readfds watched to see if characters become available for reading (or if connection request is to be accepted on a listening socket). – Descriptors in writefds watched to see if a write will not block – Descriptors in exceptfds watched for exceptions • On exit, the sets are modified in place to indicate which descriptors actually changed status. • nfds is the highest numbered descriptor in any of the three sets, plus 1. nfd can be as large as FD_SETSIZE , maximum number of file descriptors allowed in an fd_set • timeout is an upper bound on the amount of time elapsed before select returns. • On success, select returns the number of descriptors contained in the descriptor sets, which may be zero if the timeout expires before anything interesting happens. On error, 1 is returned. 89

Descriptor Set Manipulation Macros • Before calling select() function, we need to initialize and

Descriptor Set Manipulation Macros • Before calling select() function, we need to initialize and setup descriptor sets • Four macros are provided to manipulate the sets. – – FD_ZERO() clears a set. FD_SET() includes a given descriptor to a set FD_CLR() removes a given descriptor from a set. FD_ISSET tests to see if a descriptor is part of the set; this is useful after select() returns. 90

Descriptor Set Manipulation Macros (cont’d) • select(), FD_CLR(), FD_ISSET(), FD_ZERO() – used for synchronous

Descriptor Set Manipulation Macros (cont’d) • select(), FD_CLR(), FD_ISSET(), FD_ZERO() – used for synchronous I/O multiplexing FD_CLR(int fd, fd_set *set); FD_ISSET(int fd, fd_set *set); FD_ZERO(fd_set *set); 91

Example With select() From Linux Manual #include <stdio. h> #include <sys/time. h> #include <sys/types.

Example With select() From Linux Manual #include <stdio. h> #include <sys/time. h> #include <sys/types. h> #include <unistd. h> int main(void) { fd_set rfds; struct timeval tv; int retval; /* Watch stdin (fd 0) to see when it has input. */ FD_ZERO(&rfds); FD_SET(0, &rfds); 92

Example (cont’d) /* Wait up to five seconds. */ tv. tv_sec = 5; tv.

Example (cont’d) /* Wait up to five seconds. */ tv. tv_sec = 5; tv. tv_usec = 0; retval = select(1, &rfds, NULL, &tv); if (retval) printf("Data is available now. n"); /* FD_ISSET(0, &rfds) will be true. */ else printf("No data within five seconds. n"); exit(0); } 93

Observations • In the program – Notice that file descriptor for stdin is 0

Observations • In the program – Notice that file descriptor for stdin is 0 (which is standard on LINUX system) – FD_ZERO() macro clears set rfds – FD_SET() macro include file descriptor of stdin i. e. 0 in set rfds – n is set to 0 + 1 = 1 for select() function – Timeout value for select() function is set to 5 seconds 94

Uses of select() Function in Client-Server Programming • A very useful system function for

Uses of select() Function in Client-Server Programming • A very useful system function for non blocking I/O and socket read/write operations • Can be used to watch several sockets simultaneously whether some data/connection request is available in any one of them • As soon as some data is available in one of the sockets, data can be read (since select() returns after status change of descriptors) • Timeout can be exercised while watching for data arrivals on sockets 95

Example: UDP Client with select Function // UDP Client for an UDP Echo Server

Example: UDP Client with select Function // UDP Client for an UDP Echo Server // select() function is used for waiting on message #include <stdio. h> #include <sys/types. h> #include <sys/socket. h> #include <netinet/in. h> #include <arpa/inet. h> #include <netdb. h> #include <string. h> #include <stdlib. h> int main(void) { struct sockaddr_in serv. Addr; unsigned int addrlen; int sock; struct hostent *host. Ptr; char buffer[1000]; int read. Bytes; int retcode; 96

Example (con’td) if (sock < 0){ printf("Failed to create a socketn"); exit(1); } host.

Example (con’td) if (sock < 0){ printf("Failed to create a socketn"); exit(1); } host. Ptr = gethostbyname("penguin. tamucc. edu"); if (host. Ptr == NULL) { printf("Failed to find host infon"); exit(1); } bzero((char *) &serv. Addr, sizeof(serv. Addr)); serv. Addr. sin_family = AF_INET; bcopy(host. Ptr->h_addr, (char *) &serv. Addr. sin_addr, host. Ptr->h_length); serv. Addr. sin_port = htons(8888); addrlen = sizeof(serv. Addr); 97

Example (cont’d) // // Without bind() and connect(), we need to use sendto() and

Example (cont’d) // // Without bind() and connect(), we need to use sendto() and recvfrom() for datagram exchanges we cannot use write() and read() since they do not have any address parameter char message[] = "Hello World"; if (sendto(sock, message, sizeof(message)-1, 0, (struct sockaddr*) &serv. Addr, addrlen) < 0){ printf("Failed to send messagen"); exit(1); } printf("Sent: %sn", message); // Receive only if some message is waiting struct timeval T; T. tv_sec = 10; // 10 second delay T. tv_usec = 0; 98

Example (cont’d) fd_set readset; int nfds; FD_ZERO(&readset); FD_SET(sock, &readset); nfds = sock + 1;

Example (cont’d) fd_set readset; int nfds; FD_ZERO(&readset); FD_SET(sock, &readset); nfds = sock + 1; if(select(nfds, &readset, NULL, &T) < 0) { printf("Failed to execute the select() function n"); exit (1); } if(FD_ISSET(sock, &readset)) { read. Bytes = recvfrom(sock, buffer, 999, 0, (struct sockaddr*) host. Ptr, &addrlen); if (read. Bytes < 0) { printf("Failed to receive message backn"); exit(1); } buffer[read. Bytes] = ''; printf("Received: %sn", buffer); } else printf("No response received from server in 10 secondsn"); return 0; } 99

Implementing Concurrent Server Using select • select() function can be used to watch several

Implementing Concurrent Server Using select • select() function can be used to watch several sockets simultaneously Major Steps: 1. Include the sockets to be watched for status change in your fd_set 2. Call select() function with the set 3. When select() returns – – Identify the socket descriptor in the set ready to be processed Use the identified socket descriptor for computation or communication as per application 4. Repeat steps 1, 2, and 3 as necessary. 100

Example: Concurrent TCP server // Example of a concurrent server // using select() function

Example: Concurrent TCP server // Example of a concurrent server // using select() function #include <stdio. h> #include <sys/types. h> #include <sys/socket. h> #include <netinet/in. h> #include <netdb. h> #include <stdlib. h> #include <string. h> #include <unistd. h> #include <wait. h> const int SERVER_PORT = 8888; const int Q_LEN = 5; // number of waiting clients int do. Echo(int); int main(void) { struct sockaddr_in serv_sin; struct sockaddr_in cli_sin; int sock. Listen; unsigned int addr. Len; // or socklen_t addr. Len int length; 101

Example (cont’d) // Setup address structure bzero((char *) &serv_sin, sizeof(serv_sin)); serv_sin. sin_family = AF_INET;

Example (cont’d) // Setup address structure bzero((char *) &serv_sin, sizeof(serv_sin)); serv_sin. sin_family = AF_INET; serv_sin. sin_addr. s_addr = INADDR_ANY; serv_sin. sin_port = htons(SERVER_PORT); // Setup listening socket sock. Listen = socket(PF_INET, SOCK_STREAM, 0); if (sock. Listen < 0) { printf("Failed to create listening (server) socketn“); exit(1); } if (bind(sock. Listen, (struct sockaddr *) &serv_sin, sizeof(serv_sin)) < 0) { printf(" Failed to bind listening socket to addressn“); exit(1); } 102

Example (cont’d) if (listen(sock. Listen, Q_LEN) < 0){ printf("Failed to listenn“); exit(1); } addr.

Example (cont’d) if (listen(sock. Listen, Q_LEN) < 0){ printf("Failed to listenn“); exit(1); } addr. Len = sizeof(cli_sin); int nfds; fd_set readset; // read file descriptor set fd_set readset. Active; nfds =FD_SETSIZE; FD_ZERO(&readset. Active); FD_SET(sock. Listen, &readset. Active); // Wait for connection requests while (1) { bcopy(&readset. Active, &readset, sizeof(readset)); if (select(nfds, &readset, NULL, NULL) < 0){ printf("Failed to select readsetn“); exit(1); } 103

Example (cont’d) if (FD_ISSET(sock. Listen, &readset)){ int sock. Client; sock. Client = accept(sock. Listen,

Example (cont’d) if (FD_ISSET(sock. Listen, &readset)){ int sock. Client; sock. Client = accept(sock. Listen, (struct sockaddr *) &cli_sin, &addr. Len); if (sock. Client < 0){ printf("Failed to accept connectionn“); exit(1); } FD_SET(sock. Client, &readset. Active); } // Find out which socket is ready to read data from // and process for (int fd = 0; fd < nfds; ++ fd) if (fd != sock. Listen && FD_ISSET(fd, &readset)) if(do. Echo(fd) == 0){ close(fd); FD_CLR(fd, &readset. Active); } } return 0; } 104

Example (cont’d) int do. Echo(int sock. Client) { int length; // also used as

Example (cont’d) int do. Echo(int sock. Client) { int length; // also used as return code char buffer[500]; length = recv (sock. Client, buffer, sizeof(buffer), 0); if(length > 0) { if(send(sock. Client, buffer, length, 0) < 0) // Echo { printf("Failed to sendn"); length = 0; } } return length; } 105

Example (cont’d) fd_set readset; int nfds; FD_ZERO(&readset); FD_SET(sock, &readset); nfds = sock + 1;

Example (cont’d) fd_set readset; int nfds; FD_ZERO(&readset); FD_SET(sock, &readset); nfds = sock + 1; if(select(nfds, &readset, NULL, &T) < 0) { cout << "Failed to execute the select() function " << endl; exit (1); } if(FD_ISSET(sock, &readset)) { read. Bytes = recvfrom(sock, buffer, 999, 0, (struct sockaddr*) host. Ptr, &addrlen); if (read. Bytes < 0) { cout << "Failed to receive message back" << endl; exit(1); } buffer[read. Bytes] = ''; cout << "Received: " << buffer << endl; } else cout << "No response received from server in 10 seconds" << endl; } 106