Presentation is loading. Please wait.

Presentation is loading. Please wait.

Programming with TCP/IP

Similar presentations


Presentation on theme: "Programming with TCP/IP"— Presentation transcript:

1 Programming with TCP/IP
by Dr. Yingwu Zhu

2 Socket programming Goal: learn how to build client/server application that communicate using sockets Socket API introduced in BSD4.1 UNIX, 1981 explicitly created, used, released by apps client/server paradigm two types of transport service via socket API: unreliable datagram reliable, byte stream-oriented a host-local, application-created/owned, OS-controlled interface (a “door”) into which application process can both send and receive messages to/from another (remote or local) application process socket

3 Socket-programming using TCP
Socket: a door between application process and end-end-transport protocol (UCP or TCP) TCP service: reliable transfer of bytes from one process to another controlled by application developer controlled by application developer process TCP with buffers, variables socket process TCP with buffers, variables socket controlled by operating system controlled by operating system internet host or server host or server

4 Client Server Computing
two application programs must participate in any communication with one application initiates communication and the one accepts it.

5 Client Server Computing
In network applications, a SERVER application waits passively for contact after informing local protocol software that a specific type of message is expected, while a CLIENT application initiates communication actively by sending a matched type of message.

6 Identifying A Particular Service
Transport protocols assign each service a unique identifier. Both client and server specify the service identifier; protocol software uses the identifier to direct each incoming request to the correct server. In TCP/IP, TCP uses 16-bit integer values known as protocol port numbers to identify services.

7 Concurrent Server Concurrent execution is fundamental to servers because concurrency permits multiple clients to obtain a given service without having to wait for the server to finish previous requests. In concurrent server designs, the server creates a new thread or process to handle each client. Transport protocols assign an identifier to each client as well as to each service.

8 The Socket API The interface between an application program and the communication protocols in an operating system (OS) is known as the Application Program Interface or API. Sockets provide an implementation of the SAP (Service Access Point) abstraction at the Transport Layer in the TCP/IP protocol suite, which is part of the BSD Unix.

9 Socket A socket library can provide applications with a socket API on an operating system that does not provide native sockets (e.g. Windows 3.1). When an application calls one of the socket procedures, control passes to a library routine that makes one or more calls to the underlying OS to implement the socket function. A socket may be thought of as a generalization of the BSD Unix file access mechanism (open-read-write-close) that provides an end-point for communication.

10 Socket When an application creates a socket, the application is given a small integer descriptor used to reference the socket. If a system uses the same descriptor space for sockets and other I/O, a single application can be used for network communication as well as for local data transfer. An application must supply many details for each socket by specifying many parameters and options (e.g. an application must choose a particular protocol, provide address of remote machine, specify whether it is a client or server, etc.)

11 Functions needed Specify local and remote communication endpoints
Initiate a connection Wait for incoming connection Send and receive data Terminate a connection gracefully Error handling

12 Socket system calls for
read() connection establishment Server (connection-oriented protocol) blocks until connection from client Client socket() bind() listen() accept() write() connect() process request data (request) data (reply) Socket system calls for connection-oriented protocol

13 Socket system calls for connectionless protocol
Server (connectionless protocol) socket() blocks until data received from client bind() recvfrom() sendto() revfrom() process request data (request) data (reply) Client Socket system calls for connectionless protocol Not necessary in UDP!!

14 Data communication between two hosts on the Internet require the five components of what is called an association to be initialized: {protocol,local-addr, local-process/port #, remote-addr, remote-process/port#} The different system calls for sockets provides values for one or more of these components.

15 Socket system call The first system call any process wishing to do network I/O has to call is the socket system call. int sockfd = socket (int family, int type, int protocol) Examples of Family include: AF_UNIX AF_INET Examples of Type include SOCK_STREAM SOCK_DGRAM SOCK_RAW

16 Socket system call The protocol argument is typically zero, but may be specified to request an actual protocol like UDP, TCP, ICMP, etc. The socket system call just fills in one element of the five-tuple we’ve looked at - the protocol. The remaining are filled in by the other calls as shown in the figure.

17 Socket system call socket() bind() accept() connect() recvfrom()
Connection-Oriented Server Connection-oriented Client Connectionless Server Connectionless Client socket() bind() accept() connect() recvfrom() sendto() local_addr, local_process foreign_addr, foreign_process protocol

18 Specifying an Endpoint Address
Remember that the sockets API is generic There must be a generic way to specify endpoint addresses TCP/IP requires an IP address and a port number for each endpoint address. Other protocol suites(families) may use other schemes. Generic socket addresses (The C function that make up the sockets API expect structures of type sockaddr.) : struct sockaddr { unsigned short sa_family; //specifies the address type char sa_data[14]; //specifies the address value }; The sa_family field specifies the type of protocol. For TCP/IP, this field is always set to AF_INET. The remaining 14 bytes (sa_data) of this structure are always protocol dependent. For TCP/IP, IP addresses and port numbers are placed in this field. To facilitate operating with these fields, a specific type of socket address structure is used instead of the one above.

19 AF_INET--TCP/IP address
For AF_INET we need: 16 bit port number 32 bit IP address (IPv4 only) struct sockaddr_in{ short sin_family; unsigned short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; how these fields to be set and interpreted? If it's not already apparent, these structures are compatible with each other. They both are 16 bytes in size. It is also readily seen that the first two bytes of each structure are the family field. Thus, a struct sockaddr_in can always be cast to a struct sockaddr. A sockaddr_in structure contains an in_addr structure as a member field. It has the following form struct in_addr { unsigned long s_addr; }; Browsing the header file reveals that this really isn't the form of the structure. It's really a very complicated union designed to hold an IP address in a variety of ways. Regardless, the in_addr struct is exactly 4 bytes long, which is the same size as an IP address.

20 Network Byte Order Functions
Example: struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(9999); sin.sin_addr.s_addr = inet_addr; unsigned short htons(unsigned short); unsigned short ntohs(unsigned short); unsigned long htonl(unsigned long); unsigned long ntohl(unsigned long); n the above code example, the structure sin, holds the IP address, , and references the port number Two utility functions are used to set these values. The function htons returns the integer argument passed into it in network byte order. The function inet_addr converts the string argument from a dotted-quad into a 32-bit integer. Its return value is also in network byte order. ‘h’ : host byte order ‘n’ : network byte order ‘s’ : short (16 bit) unsigned ‘l’ : long(32 bit) unsigned

21 Bind System Call The bind system call assigns an address to an unnamed socket. Example: int bind(int sockfd, struct sockaddr_in *myaddr, int addrlen)

22 Bind System Call What is bind used for ?
Servers (both connection oriented and connectionless) NEED to register their well-known address to be able to accept connection requests. A client can register a specific address for itself. A connectionless client NEEDS to assure that it is bound to some unique address, so that the server has a valid return address to send its responses to – However, it does not have to bind to a particular port! WHY?

23 The bind system call provides the values for the local_addr and local_process/port # elements in the five_tuple in an association. An address for the Internet domain sockets is a combination of a hostname and a port number, as shown below: struct sockaddr_in { short sin_family ; /*typically AF_INET*/ u_short sin_port; /* 16 bit port number, network byte ordered */ struct in_addr sin_addr ; /* 32 bit netid/hostid, network byte ordered */ char sin_zero[8]; /* unused*/ }

24 Connect/Listen/Accept System Calls
A client process connects a socket descriptor after a socket system call to establish a connection with the server. int connect(int sockfd, struct sockaddr_in *servaddr, int addrlen) For a connection-oriented client, the connect (along with an accept at the server side) assigns all four addresses and process components of the association.

25 Listen Listen The listen system call is used by a connection-oriented server to indicate it is willing to receive connections. int listen(int socket, int qlength) allows servers to prepare a socket for incoming connections puts the socket in a passive mode ready to accept connections informs the OS that the protocol software should enqueue multiple simultaneous requests that arrive at the socket applies only to sockets that have selected reliable stream delivery service

26 Accept Accept After the connection-oriented server executes a listen, it waits for connection requests from client(s) in the accept system call, e.g., newsockfd = accept(sockfd, peer, addrlen) needs to wait for a connection blocks until a connection request arrives addrlen is a pointer to an integer; when a request arrives , the system fills in argument addr with the address of the client that has placed the request and sets addrlen to the length of the address. system creates a new socket, returns the new socket descriptor

27 Accept accept returns a new socket descriptor, which has all five components of the association specified - three (protocol, local addr, local_process) are inherited from the existing sockfd (which however has its foreign address and process components unspecified, and hence can be re-used to accept another request. This scenario is typical for concurrent servers.

28 Sending and Receiving Data
Here’s how you might read from a socket: num_read = read(sockfd, buff_ptr, num_bytes) And here’s how you read from an open file descriptor in Unix: num_read = read(fildes, buff_ptr, num_bytes) There are other ways (with different parameters) to send and receive data: read, readv, recv, recvfrom, recvmsg to receive data through a socket; and write, writev, send, sendto, sendmsg to send data through a socket.

29 sendto()--UDP Sockets
int sendto(int socket, char *buffer, int length, int flags, struct sockaddr *destination_address, int address_size); For example: struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(12345); sin.sin_addr.s_addr = inet_addr(" "); char *msg = "Hello, World"; sendto(s, msg, strlen(msg)+1, 0, (struct sockaddr *)sin, sizeof(sin)); Once a UDP socket has been created and bound to a local source port, it is now capable of being used for sending and receiving datagrams. The functions for sending and receiving datagrams are sendto and recvfom. Sendto has the following prototype: int sendto(int socket, char *buffer, int length, int flags, struct sockaddr *destination_address, int address_size); Where socket is a UDP socket that has been created and bound to a source port. buffer is a pointer to an array of bytes that are to be sent over the network. The length field specifies how long this array is. The flags field is normally 0. In the above example, s is assumed to be a created UDP socket that has already bound to a local port. When sendto is called, a UDP datagram is sent to the host at It's assumed there is a process with a socket bound to port waiting on a recvfrom call to receive the contents of the message being sent. The sendto function returns the number of bytes sent, or -1 if an error occurred. With UDP sockets, it's not usually necessary to check to see how many bytes were sent because this information is specified in the length field.

30 recvfrom()--UDP Sockets
Int recvfrom(int socket, char *buffer, int length, int flags, struct sockaddr *sender_address, int *address_size) For example: struct sockaddr_in sin; char msg[10000]; int ret; int sin_length; sin_length = sizeof(sin); ret = recvfrom(s, msg, 10000, 0, (struct sockaddr *)sin, &sin_length); printf("%d bytes received from %s (port %d)\n", ret, inet_ntoa(sin.sin_addr), sin.sin_port); Recvfrom is similar to sendto. Buffer is a pointer to a byte array that is to be filled with the contents of the datagram. The length argument specifies the maximum length to copy into buffer. This is to prevent buffer over-run errors in case the datagram is larger than expected. The flags field is normally 0. The sender_address argument is a pointer to a socket address structure that gets filled with a copy of the sender's IP address and source port. The address_size parameter must be initialized to the size of the sockaddr structure being used. On return it will hold the number of bytes that were copied into the sender_address structure. Recvfrom returns the number of bytes copied into the byte array pointed to by buffer. If the buffer space specified in length is less than that of the original datagram, only length bytes will be copied into buffer, and the rest will be lost. In the above example, recvfrom will wait until it receives a datagram on the local port associated with the socket s. The printf statement will list information regarding the size, source IP address, and source port of the datagram received. For any open socket that has been successfully binded to a port, the application may call sendto and recvfrom using that socket as many times as it needs to. Fragmentation is completely transparent to the applications that are sending and receiving datagrams.

31 send() and recv() -- TCP Sockets
int send(int s, const char *msg, int len, int flags) connected socket argument flags controls the transmission. allows the sender to specify that the message should be sent out-of- band messages correspond to TCP’s urgent data allows the caller to request that the message be sent without using local routine tables (take control of routine) int recv(int s, char *buf, int len, int flags) argument flags allow the caller to control the reception look ahead by extracting a copy of the next incoming message without removing the message from the socket NAME send, sendto, sendmsg - send a message from a socket #include <sys/types.h> #include <sys/socket.h> int send(int s, const char *msg, int len, int flags); int sendto(int s, const char *msg, int len, int flags, const struct sockaddr *to, int tolen); int sendmsg(int s, const struct msghdr *msg, int flags); send(), sendto(), and sendmsg() are used to transmit a message to another transport end-point. send() may be used only when the socket is in a connected state, while sendto() and sendmsg() may be used at any time. s is a socket created with socket(3N). The address of the target is given by to with tolen specifying its size. The length of the message is given by len. If the message is too long to pass atomically through the underlying protocol, then the error EMSGSIZE is returned, and the message is not transmitted. A return value of -1 indicates locally detected errors only. It does not implicitly mean the message was not delivered. If the socket does not have enough buffer space available to hold the message being sent, send() blocks.

32 close() and shutdown()
close(int socket) For UDP sockets, this will release the ownership on the local port that is bound to this socket For TCP, this will initiate a two-way shutdown between both hosts before giving up port ownership. shutdown(int socket, int how) f the how field is 0, this will disallow further reading (recv) from the socket. If the how field is 1, subsequent writes (send) will be disallowed. The socket will still need to be passed to close. If a TCP socket calls close, any pending or subsequent recv calls by the remote host will result in recv returning 0 to indicate a connection shutdown on the other end has occurred. Attempting to call send on a socket that is connected to a host that has called close will result in send returning -1. Unless it's known a priori that the remote host has only called shutdown, it is recommended that the application call close on it's socket so that the TCP connection will be properly terminated on both sides.

33 Relationship Between Sockets and File Descriptors
Socket handles are integer values. In UNIX, socket handles can be passed to most of the low-level POSIX I/O functions. read(s, buffer, buff_length); //s could be a file descriptor too write(s, buffer, buff_length) ; In the above example, s could be either a socket or file handle. Calling read on an open socket is equivalent to recv and recvfrom. However, if the socket is UDP, then information about the sender of the datagram will not be returned. Similarly the write function call is equivalent to send and sendto. UDP sockets may call connect to use send and write. It's always recommended that the socket library functions be used instead of the file I/O equivalents.

34 Utility Functions unsigned int inet_addr(char *str)
str represents an IP address(dotted-quad notation); inet_addr will return it's equivalent 32-bit value in network byte order. This value can be passed into the sin_addr.s_addr field of a socketaddr_in structure -1 is returned if the string can not be interpreted char *inet_ntoa(struct in_addr ip) Converts the 32-bit value which is assumed to be in network byte order and contained in ip to a string The pointer returned by inet_ntoa contains this string. However, subsequent calls to inet_ntoa will always return the same pointer, so copying the string to another buffer is recommended before calling again.

35 Utility Functions ( cont’d )
int gethostname(char *name, int length) Copies the name (up to length bytes) of the hostname of the local computer into the character array pointed to by name struct hostent *gethostbyname(char *strHost) int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout) – later!!! f the string contained in strHost represents a host name (such as "rain" or "rain.cise.ufl.edu"), gethostbyname will return a pointer to a hostent structure containing additional information about the host including additional names and IP addresses associate with that host. Gethostbyname will does all the work of looking up address entries in local database files as well as making DNS queries. NULL is returned if the host name is unknown. The format for the hostent structure is as follows: struct hostent { char * h_name; /* official name of host */ char ** h_aliases; /* alias list */ short h_addrtype; /* host address type */ short h_length; /* length of address */ char ** h_addr_list; /* list of addresses */ #define h_addr h_addr_list[0] /* address, for backward compat */ }; In short, the first IP address is contained within the first 4 bytes of the first entry in h_addr_list. h_addr can be used to reference this value. Using gethostbyname and inet_addr, a very good resolver function can be written to convert strings the user types as Internet addresses into equivalent 32-bit numbers for socket calls.

36 Others Include files Compiling and Linking Programming tips
#include <sys/types.h>; #include <sys/socket.h>; #include <netinet/in.h>; #include <arpa/inet.h>; #include <netdb.h>; #include <unistd.h>; #include <signal.h>; #include <stdio.h>; #include <fcntl.h>; #include <errno.h; #include <sys/time.h>; #include <stdlib.h>; #include <memory.h>; Compiling and Linking Under most versions of UNIX (Linux, BSD, SunOS, IRIX) compiling is done as usual: gcc my_socket_program.c -o my_socket_program Solaris: cc my_socket_program.c -o my_socket_program -lsocket -lnsl Programming tips always check the return value for each function call consult the UNIX on-line manual pages ("man") for a complete description

37 Example: Socket programming with TCP
Example client-server app: client reads line from standard input, sends to server via socket server reads line from socket server converts line to uppercase, sends back to client client reads, prints modified line from socket Input stream: sequence of bytes into process Output stream: sequence of bytes out of process outToServer iinFromServer inFromUser client socket

38 Client/server socket interaction: TCP
Server (running on hostid) Client create socket, port=x, for incoming request: int s = socket(…); bind(s,…) listen(s,5); TCP connection setup close cs read reply from cli_socket create socket, connect to hostid, port=x int cli_socket = socket(..); connect(s,…); wait for incoming connection request int cs = accept(s,….) send request using cli_socket read request from cs write reply to

39 Example: C++ client (TCP)
#include <stdio.h> /* Basic I/O routines */ #include <sys/types.h> /* standard system types */ #include <netinet/in.h> /* Internet address structures */ #include <sys/socket.h> /* socket interface functions */ #include <netdb.h> /* host to IP resolution */ int main(int argc, char *argv[]) { /* Address resolution stage */ struct hostent* hen = gethostbyname(argv[1]); if (!hen) { perror("couldn't resolve host name"); } struct sockaddr_in sa; memset(&sa, 0, sizeof(sa); sa.sin_family = AF_INET; sa.sin_port = htons(PORT); //server port number memcpy(&sa.sin_addr.s_addr, hen->h_addr_list[0], hen->h_length); int cli_socket = socket(AF_INET, SOCK_STREAM, 0); assert(cli_socket >= 0); //I am just lazy here!! connect(s, (struct sockaddr *)&sa, sizeof(sa)); write(s, argv[2], strlen(argv[2])); //send it to server char buf[BUFLEN]; int rc; memset(buf, 0, BUFLEN); char* pc = buf; while(rc = read(cli_socket, pc, BUFLEN – (pc - buf))) pc += rc; write(1, buf, strlen(buf)); close(cli_socket); Create client socket, connect to server

40 Example: C++ server (TCP)
//include header files #define PORT 6789 int main(int argc, char* argv[]) { struct sockaddr_in sa, csa; memset(&sa, 0, sizeof(sa); sa.sin_family = AF_INET; sa.sin_port = htons(PORT); sa.sin_addr.s_addr = INADDR_ANY; //any IP addr. Is accepted int s = socket(AF_INET,SOCK_STREAM, 0); assert( s>=0); int rc = bind(s, (struct sockaddr *)& sa, sizeof(sa)); //hook s with port rc = listen(s, 5); int cs_socket = accept(s, (struct sockaddr*)&csa, sizeof(csa)); char buf[BUFLEN]; memset(buf, 0, BUFLEN); char* pc = buf; while(rc = read(cs_socket, pc, BUFLEN – (pc - buf))) pc += rc; upper_case(buf); // covert it into upper case write(cs_socket, buf, strlen(buf)); close(cs_socket); close(s); }

41 Multi-Clients Servers
Two main approaches to designing such servers. Approach 1. The first approach is using one process that awaits new connections, and one more process (or thread) for each Client already connected. This approach makes design quite easy, cause then the main process does not need to differ between servers, and the sub-processes are each a single-Client server process, hence, easier to implement. However, this approach wastes too many system resources (if child processes are used), and complicates inter-Client communication: If one Client wants to send a message to another through the server, this will require communication between two processes on the server, or locking mechanisms, if using multiple threads. See tutor for details!

42 Socket programming with UDP
UDP: no “connection” between client and server no handshaking sender explicitly attaches IP address and port of destination server must extract IP address, port of sender from received datagram UDP: transmitted data may be received out of order, or lost application viewpoint UDP provides unreliable transfer of groups of bytes (“datagrams”) between client and server

43 Summary Network Application Programming Interface (API) TCP/IP basic
UNIX/C Sockets socket() ; bind() ; connect() ; listen() ; accept() ; sendto() ; recvfrom(); send() ; recv() ; read() ; write(); some utility functions


Download ppt "Programming with TCP/IP"

Similar presentations


Ads by Google