The Sockets Library and Concepts Rudra Dutta CSC 230 - Spring 2007, Section 001 API for Network Apps Interface between TCP/IP and applications only loosely specified The standards suggest the functionality (not the details) – allocate resources for communication – specify communication endpoints – initiate a connection (client) or wait for incoming connection (server) – send or receive data – terminate a connection gracefully – handle error conditions – etc. Copyright Rudra Dutta, NCSU, Spring 2002 2 Unix File I/O Program calls open() to initiate input or output – returns a file descriptor (small, positive integer) Calls to read() or write() to transfer data – with the file descriptor as an argument Once I/O operations are completed, the program calls close() Other relevant system calls: lseek(), ioctl() – (these are not used in the Sockets API) Copyright Rudra Dutta, NCSU, Spring 2002 3 Unix File I/O Example int fd; char buf[256]; fd = open("a.txt", ORDWR | O_CREAT); write(fd, buf, sizeof(buf)); close(fd); Roughly the same for sockets, except for setup Copyright Rudra Dutta, NCSU, Spring 2002 4 Socket API Introduced in 1981 by BSD 4.1 – – implemented as system calls originally only Unix but WinSock almost the same Mainly, two services – – datagram (UDP) stream (TCP) Copyright Rudra Dutta, NCSU, Spring 2002 5 The Socket Abstraction Provides an endpoint for communication – – also provides buffering sockets are not bound to specific addresses at the time of creation Identified by small integer, the socket descriptor Flexibility – – – functions that can be used with many different protocols programmer specifies the type of service required, rather than the protocol number a generic address structure Copyright Rudra Dutta, NCSU, Spring 2002 6 Endpoint Addresses Each socket association has five components – – – – – protocol local address local port remote address remote port protocol: used by socket() local address, port: bind() remote address, port: connect(), sendto() Copyright Rudra Dutta, NCSU, Spring 2002 7 Creating A Socket int s = Parameters – – – socket(domain, type, protocol); domain: PF_INET type: SOCK_DGRAM, SOCK_STREAM, SOCK_RAW protocol: usually = 0 (i.e., default for type) Example #include <sys/types.h> #include <sys/socket.h> … if ((s = socket(PF_INET, SOCK_STREAM, 0) < 0) perror("socket"); Copyright Rudra Dutta, NCSU, Spring 2002 8 After Creating A Socket (cont'd) Copyright Rudra Dutta, NCSU, Spring 2002 9 Generic Address Structure Each protocol family defines its own address representation For each protocol family there is a corresponding address family – (e.g., PF_INET AF_INET, PF_UNIX AF_UNIX) Generalized address format: – <address family, endpoint address in family> struct sockaddr { u_char sa_len; u_short sa_family; char /* total length */ /* type of address */ sa_data[14]; /* value of address */ }; Copyright Rudra Dutta, NCSU, Spring 2002 10 Socket Addresses, Internet Style #include <netinet/in.h> struct in_addr { u_long s_addr; /* 32-bit host address */ }; struct sockaddr_in { u_char sin_len; /* total length */ short sin_family; /* AF_INET */ u_short sin_port; /* network byte order */ struct in_addr sin_addr; char /* network address */ sin_zero[8]; /* unused */ }; Copyright Rudra Dutta, NCSU, Spring 2002 11 Binding the Local Address int bind(int s, struct sockaddr *addr, int addrlen); Used primarily by servers to specify their well-known port Optional for clients – normally, system chooses a “random” local port Use INADDR_ANY to allow the socket to receive datagrams sent to any of the machine's IP addresses Copyright Rudra Dutta, NCSU, Spring 2002 12 Binding the Local Address (cont'd) … sin.sin_family sin.sin_port chooses */ sin.sin_addr.s_addr interface */ if (bind(s, (struct /* error function Copyright Rudra Dutta, NCSU, Spring 2002 = AF_INET; = htons(6000); /* if 0:system = INADDR_ANY; /* allow any sockaddr *)&sin, sizeof(sin)) < 0) here */ 13 After Binding the Local Address Copyright Rudra Dutta, NCSU, Spring 2002 14 Establish a Connection Queue int listen(int s, int backlog); Only used for stream sockets Used by connection-oriented servers to place a socket in passive mode – – makes it ready to accept incoming connections the remote port # / IP address of the socket = 0 (any port, any IP address) Allows backlog pending connections to be waiting for accept() Copyright Rudra Dutta, NCSU, Spring 2002 15 Accepting Connection Requests newsock = Executed by connection-oriented server, after listen() – accept(int s, struct sockaddr *clientaddr, int *clientaddrlen); blocks until a connection request from a client arrives Returns a new, unique socket (newsock) for data exchange with the client – – this new socket is for the connection with port # / IP address of the client as the remote port and IP address this new socket must be closed when the client and server are through communicating Copyright Rudra Dutta, NCSU, Spring 2002 16 Accepting Connection Requests The original socket s (with 0 as remote address) remains open – when a TCP segment arrives for this host/port, and no existing socket has a remote IP address / port # = to the source IP address/port of the segment, the segment will be sent to the original socket s Must call accept() again to obtain the next connection request Copyright Rudra Dutta, NCSU, Spring 2002 17 Accepting Connections (cont'd) Copyright Rudra Dutta, NCSU, Spring 2002 18 Connecting To A Server int Binds a permanent destination to a socket – uses 3-way handshake to establish connection (active open) As a side effect, it chooses a local endpoint (IP address and port number) if the socket does not have one – connect(int s, struct sockaddr *servername, int servernamelen); Cients normally let the system choose their (ephemeral) port # May fail – – host not listening to port timeout Copyright Rudra Dutta, NCSU, Spring 2002 19 Client-Server Interaction: TCP Copyright Rudra Dutta, NCSU, Spring 2002 20 Sending and Receiving Data Types – – – Options: flags which modify action of a call – read(), write() recv(), send() recvfrom(), sendto() read() and write() may not specify options Notes – – block size read may not = block size written read from stream may read fewer bytes than requested Copyright Rudra Dutta, NCSU, Spring 2002 21 Sending Data int write(int s, char* buf, int buflen); int send(int s, char* buf, int buflen, int flags); Flags control transmission – E.g., specify urgent data Write might not be able to write all buflen bytes (on a nonblocking socket) Copyright Rudra Dutta, NCSU, Spring 2002 22 Receiving Data int read(int s, char* buf, int buflen); int recv(int s, char* buf, int buflen, int flags); Flags control reception, e.g., – – Reminder! – – out-of-band data message look-ahead block size read may not = block size written read from stream may read fewer bytes than requested If the other end has closed the connection, and there is no buffered data, reading from a TCP socket returns 0 to indicate EOF Copyright Rudra Dutta, NCSU, Spring 2002 23 Closing A Connection int Actions – – close(int s); decrements reference count for socket terminates communication gracefully and removes socket when reference count = 0 Problem – server does not know if client has additional requests – client does not know if server has additional data to send Copyright Rudra Dutta, NCSU, Spring 2002 24 Partially Closing A Connection int shutdown(int s, int direction); Direction – 0 to close the input (reading) end – 1 to close the output (writing) end – 2 for both Used by client to specify it has no more data to send, without deallocating connection Server receives an EOF signal on read() or recv(), can then close connection after sending its last response Copyright Rudra Dutta, NCSU, Spring 2002 25 Datagram Communication int sendto(int s, char *buf, int buflen, int flags, struct sockaddr *to, int tolen); First 4 arguments same as in send() Sends buflen bytes in buffer buf to location to, with options flags (usually 0) The return value of sendto() indicates how much data was accepted by the O.S. for sending as a datagram – – not how much data made it to the destination there is no error condition that indicates the destination did not get the data! Copyright Rudra Dutta, NCSU, Spring 2002 26 Datagram Communication (cont’d) int recvfrom(int s, char *buf, int buflen, int flags, struct socaddr *from, int fromlen); First 4 arguments same as in recv() Receives up to len bytes into buffer buf – – returns number of bytes received, 0 on EOF if buf is not large enough, any extra data is lost forever recvfrom blocks until datagram available, by default Sets from to source address of data – sending replies is easy Copyright Rudra Dutta, NCSU, Spring 2002 27 Connected vs. Unconnected UDP Sockets UDP sockets can be connected or unconnected – – in connected mode, client uses connect() to specify a remote endpoint convenient to interact with a specific server repeatedly connect(): only records the remote address, does not initiate any packet exchange write(): sends a single message to the server read(): returns one complete message Copyright Rudra Dutta, NCSU, Spring 2002 28 Closing UDP Sockets close() – – releases the resources associated with a socket does not inform the remote endpoint that the socket is closed shutdown() – – can be used to mark socket as unwilling to transfer data in the direction specified does not send any message to the other side Copyright Rudra Dutta, NCSU, Spring 2002 29 Client-Server Interaction: UDP • Contrast with TCP Copyright Rudra Dutta, NCSU, Spring 2002 30 Byte Ordering Representation Copyright Rudra Dutta, NCSU, Spring 2002 31 Byte-Order Transformations Copyright Rudra Dutta, NCSU, Spring 2002 32 Byte-Order Transformations (cont’d) Byte ordering is a function of machine architecture – – – Intel: little-endian Sparc, PowerPC: big-endian Network order: big-endian Functions – u_long m = – – htonl(u_long m) host-to-network byte order, 32 bit ntohs(), network-to-host byte order, 32 bit u_long m = ntohl(u_long m) htons() short (16 bit) Be safe; it never hurts to use, and it improves portability Copyright Rudra Dutta, NCSU, Spring 2002 33 Address Conversions Internally, IP addresses are represented as 32-bit integers int addr = inet_addr(char *str) addr: network byte order, str: dotted decimal form char *str = Copyright Rudra Dutta, NCSU, Spring 2002 inet_ntoa(struct in_addr in) 34 Obtaining Information About Hosts, etc. struct hostent *hptr; address in /* includes host binary */ hptr = gethostbyname(char *name); Ex.: gethostbyname(“www.csc.ncsu.edu”); struct hostent *hptr; hptr = gethostbyaddr(char *addr, int addrlen, int addrtype); Ex.: gethostbyaddr(&addr, 4, AF_INET); Copyright Rudra Dutta, NCSU, Spring 2002 35 Obtaining Information int inet_addr(char *dotdecimal); Ex.: sin_addr = inet_addr(“152.14.51.129”); struct servent *sptr; /* includes port and protocol */ sptr = getservbyname(char *name, char *proto); Ex.: getservbyname(“smtp”, “tcp”); struct protoent *pptr; /* includes protocol number */ pptr = getprotobyname(char *name); Ex.: getprotobyname(“tcp”); Copyright Rudra Dutta, NCSU, Spring 2002 36 Example of Connection Establishment // host - name of host to which connection is desired // service - service associated with the desired port // transport - name of transport protocol to use ("tcp“, "udp") memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; /* Map service name to port number */ if ( pse = getservbyname(service, transport) ) sin.sin_port = pse->s_port; else if ((sin.sin_port = htons((unsigned short)atoi(service))) == 0) errexit("can't get \"%s\" service entry\n", service); Copyright Rudra Dutta, NCSU, Spring 2002 37 Example (cont’d) /* Map host name to IP address, allowing for dotted decimal */ if ( phe = gethostbyname(host) ) memcpy(&sin.sin_addr, phe->h_addr, phe->h_length); else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE ) errexit("can't get \"%s\" host entry\n", host); /* Map transport protocol name to protocol number */ if ( (ppe = getprotobyname(transport)) == 0) errexit("can't get \"%s\" protocol entry\n", transport); Copyright Rudra Dutta, NCSU, Spring 2002 38 Example (cont’d) /* Use protocol to choose a socket type */ if (strcmp(transport, "udp") == 0) type = SOCK_DGRAM; else type = SOCK_STREAM; /* Allocate a socket */ s = socket(PF_INET, type, ppe->p_proto); if (s < 0) errexit("can't create socket: %s\n", strerror(errno)); Copyright Rudra Dutta, NCSU, Spring 2002 39 Example (cont’d) /* Connect the socket */ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) errexit("can't connect to %s.%s: %s\n", host, service, strerror(errno)); return s; Copyright Rudra Dutta, NCSU, Spring 2002 40