220 likes | 226 Views
EE 122: Sockets. Kevin Lai September 11, 2002. Motivation. Applications need Application Programming Interface (API) to use the network API: set of function types and data structures and constants Desirable characteristics Standardized allows programmer to learn once, write anywhere
E N D
EE 122: Sockets Kevin Lai September 11, 2002
Motivation • Applications need Application Programming Interface (API) to use the network • API: set of function types and data structures and constants • Desirable characteristics • Standardized • allows programmer to learn once, write anywhere • Flexible • support multiple protocols • Simple to use • Complete • allows program to use all functionality of a protocol • protocols and APIs usually evolve in parallel laik@cs.berkeley.edu
Sockets • Berkeley sockets is the most popular network API • runs on Linux, FreeBSD, OS X, Windows • fed/fed off of popularity of TCP/IP • Supports TCP/IP, UNIX interprocess communication • Similar to UNIX file I/O API • Based on C, single threaded model • does not require multiple threads • Can build higher-level interfaces on top of sockets • e.g., Remote Procedure Call (RPC) laik@cs.berkeley.edu
Types of Sockets • Different types of sockets implements different service models • Stream v.s. datagram • Stream socket • connection-oriented • reliable, in order delivery • e.g., ssh, http • Datagram socket • connectionless • “best-effort” delivery, possibly lower delay • e.g., IP Telephony laik@cs.berkeley.edu
Chat Client • create stream socket • connect to server • while still connected: • if user types data, send to server • if receive data from server, print laik@cs.berkeley.edu
Naming and Addressing • IP Address • identifies a single host • 32 bits (not a number!) • written as dotted octets • e.g., 0x0a000001 is 10.0.0.1 • Host name • identifies a single host • variable length string • maps to one or more IP address • e.g., www.berkeley.edu • Port number • identifies an application on a host • 16 bit number laik@cs.berkeley.edu
Presentation • Different CPU architectures have different byte ordering • why? • Many errors for novice network programmers increasing memory addresses address A +1 address A little-endian high-order byte low-order byte 16-bit value big-endian low-order byte high-order byte laik@cs.berkeley.edu
Byte Ordering Solution uint16_t htons(uint16_t host16bitvalue); uint32_t htonl(uint32_t host32bitvalue); uint16_t ntohs(uint16_t net16bitvalue); uint32_t ntohs(uint32_t net32bitvalue); • Use for all integers sent across network • including port numbers, but not IP addresses • Floating point numbers • no widely used standard laik@cs.berkeley.edu
Initializing (1) • allocate socket int chat_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); laik@cs.berkeley.edu
Initializing (2) int chat_sock; if ((chat_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("socket"); printf("Failed to create socket\n"); abort (); } • Why would socket() fail? • Handling errors that occur rarely usually consumes most of systems code • exceptions (e.g., in java) helps this a somewhat laik@cs.berkeley.edu
Connecting (1) struct sockaddr_in sin; struct hostent *host = gethostbyname (argv[1]); unsigned int server_addr = *(unsigned long *) host->h_addr_list[0]; unsigned short server_port = atoi (argv[2]); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(server_addr); sin.sin_port = server_port; connect(chat_sock, (struct sockaddr *) &sin, sizeof(&sin)); laik@cs.berkeley.edu
Connecting (2) struct sockaddr_in sin; struct hostent *host = gethostbyname (argv[1]); unsigned int server_addr = *(unsigned long *) host->h_addr_list[0]; unsigned short server_port = atoi (argv[2]); memset (&sin, 0, sizeof (sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = server_addr; sin.sin_port = htons (server_port); if (connect(chat_sock, (struct sockaddr *) &sin, sizeof (sin)) < 0) { perror("connect"); printf("Cannot connect to server\n"); abort(); } laik@cs.berkeley.edu
Separating Data in a Stream • Use records to partition • Tradeoffs of two variable schemes? Fixed length Record Fixed length record Variable length record Variable length record A B C 3 C 2 0 1 2 3 4 5 6 7 8 9 Variable length record Variable length record C C 0 0 5 6 7 8 9 laik@cs.berkeley.edu
Receiving Packets (1) int received; char buffer[RECORD_LEN]; received = recv(chat_sock, buffer, RECORD_LEN, 0); process_packet(buffer, received); laik@cs.berkeley.edu
Receiving Packets (2) int receive_packets(char *buffer, int buffer_len, int *bytes_read) { int left = buffer_len - *bytes_read; received = recv(chat_sock, buffer + *bytes_read, left, 0); if (received < 0) { perror ("Read in read_client"); printf("recv in %s\n", __FUNCTION__); } if (received <= 0) { return close_connection(); } *bytes_read += received; while (*bytes_read > RECORD_LEN) { process_packet(buffer, RECORD_LEN); *bytes_read -= RECORD_LEN; memmove(buffer, buffer + RECORD_LEN, *bytes_read); } return 0; } laik@cs.berkeley.edu
I/O Multiplexing (1) while (1) { if (receive_packets(buffer, buffer_len, &bytes_read) != 0) { break; } if (read_user(user_buffer, user_buffer_len, &user_bytes_read) != 0) { break; } } laik@cs.berkeley.edu
I/O Multiplexing (2): Non-blocking int opts = fcntl (chat_sock, F_GETFL); if (opts < 0) { perror ("fcntl(F_GETFL)"); abort (); } opts = (opts | O_NONBLOCK); if (fcntl (chat_sock, F_SETFL, opts) < 0) { perror ("fcntl(F_SETFL)"); abort (); } while (1) { if (receive_packets(buffer, buffer_len, &bytes_read) != 0) { break; } if (read_user(user_buffer, user_buffer_len, &user_bytes_read) != 0) { break; } } laik@cs.berkeley.edu
I/O Multiplexing using select() • select() • wait on multiple file descriptors/sockets and timeout • application does not consume CPU cycles while waiting • return when file descriptors/sockets are ready to be read or written or they have an error, or timeout exceeded • advantages • simple • more efficient than polling • disadvantages • does not scale to large number of file descriptors/sockets • more awkward to use than it needs to be laik@cs.berkeley.edu
I/O Multiplexing (3): select() // already set descriptors non-blocking fd_set read_set; while (1) { FD_ZERO (read_set); FD_SET (stdin, read_set); FD_SET (chat_sock, read_set); select_retval = select(MAX(stdin, chat_sock) + 1, &read_set, NULL, NULL, &time_out); if (select_retval < 0) { perror ("select"); abort (); } if (select_retval > 0) { if (FD_ISSET(chat_sock, read_set)) { if (receive_packets(buffer, buffer_len, &bytes_read) != 0) { break; } if (FD_ISSET(stdin, read_set)) { if (read_user(user_buffer, user_buffer_len, &user_bytes_read) != 0) { break; } } } } laik@cs.berkeley.edu
Other I/O Models • Signal driven • application notified when I/O operation can be initiated • achieves similar CPU efficiency as select() • Asynchronous • application notified when I/O operation is completed • can achieve higher CPU efficiency than select()/signals on architectures that have DMA and available system bus bandwidth • mainly useful for very high bandwidth I/O • Both add significant complexity relative to select() • must use locks to deal with being interrupted at arbitrary code locations • sample complexity cost as threads laik@cs.berkeley.edu
Chat Server • create stream socket • while 1: • if user connects, add to list of users • if receive data from client, send to all other clients laik@cs.berkeley.edu
Summary • Major sources of error for network programmers using sockets: • byte ordering • separating records in streams • using select() • misinterpreting the specification (not covered here) laik@cs.berkeley.edu