870 likes | 974 Views
Learn about UDP connected mode, asynchronous errors, I/O multiplexing options, and handling system calls and errors in socket programming. Explore non-blocking I/O, alarm usage, and select system call for efficient network communication.
E N D
UDP Connected mode • A UDP socket can be used in a call to connect() • This simply tells the O.S. the address of the peer • No handshake is made to establish that the peer exists • No data of any kind is sent on the network as a result of calling connect() on a UDP socket CPE 401/601 Lecture 12 : Socket Programming Issues
Connected UDP • Once a UDP socket is connected: • can use sendto() with a null dest address • can use write() and send() • can use read() and recv() • only datagrams from the peer will be returned • Asynchronous errors will be returned to the process OS Specific, some won’t do this! CPE 401/601 Lecture 12 : Socket Programming Issues
Asynchronous Errors • What happens if a client sends data to a server that is not running? • ICMP “port unreachable” error is generated by receiving host and sent to sending host • The ICMP error may reach the sending host after sendto() has already returned! • The next call dealing with the socket could return the error CPE 401/601 Lecture 12 : Socket Programming Issues
I/O Multiplexing • We often need to be able to monitor multiple descriptors: • a generic TCP client (like telnet) • a server that handles both TCP and UDP • Client that can make multiple concurrent requests • browser CPE 401/601 Lecture 12 : I/O Multiplexing
Example - generic TCP client • Input from standard input should be sent to a TCP socket • Input from a TCP socket should be sent to standard output • How do we know when to check for input from each source? STDIN TCP SOCKET STDOUT CPE 401/601 Lecture 12 : I/O Multiplexing
Options • Use multiple processes/threads • Use nonblocking I/O • use fcntl() to set O_NONBLOCK • Use alarm and signal handler to interrupt slow system calls • Use functions that support checking of multiple input sources at the same time CPE 401/601 Lecture 12 : I/O Multiplexing
Non blocking I/O • Tell kernel not to block a process if I/O requests can not be completed • use fcntl() to set O_NONBLOCK: int flags; flags = fcntl(sock,F_GETFL,0); fcntl(sock,F_SETFL,flags | O_NONBLOCK); • Now calls to read() (and other system calls) will return an error and set errno to EWOULDBLOCK CPE 401/601 Lecture 12 : I/O Multiplexing
Non blocking I/O while (! done) { if ( (n=read(STDIN_FILENO,…)<0)) if (errno != EWOULDBLOCK) /* ERROR */ else write(tcpsock,…) if ( (n=read(tcpsock,…)<0)) if (errno != EWOULDBLOCK) /* ERROR */ else write(STDOUT_FILENO,…) } CPE 401/601 Lecture 12 : I/O Multiplexing
The problem with nonblocking I/O • Using blocking I/O allows the OS to put your process to sleep when nothing is happening • Once input arrives, the OS will wake up your process and read() (or whatever) will return • With nonblocking I/O, the process will chew up all available processor time!!! CPE 401/601 Lecture 12 : I/O Multiplexing
Using alarms signal(SIGALRM, sig_alrm); alarm(MAX_TIME); read(STDIN_FILENO,…); ... signal(SIGALRM, sig_alrm); alarm(MAX_TIME); read(tcpsock,…); ... A function you write CPE 401/601 Lecture 12 : I/O Multiplexing
“Alarming” Issues • What will happen to the response time ? • What is the ‘right’ value for MAX_TIME? CPE 401/601 Lecture 12 : I/O Multiplexing
Select() • The select() system call allows us to use blocking I/O on a set of descriptors • file, socket, … • We can ask select to notify us when data is available for reading on either STDIN or a socket CPE 401/601 Lecture 12 : I/O Multiplexing
select() int select( int maxfd, fd_set *readset, fd_set *writeset, fd_set *excepset, const struct timeval *timeout); • maxfd: highest number assigned to a descriptor • readset: set of descriptors we want to read from • writeset: set of descriptors we want to write to • excepset: set of descriptors to watch for exceptions • timeout: maximum time select should wait CPE 401/601 Lecture 12 : I/O Multiplexing
Using select() • Create fd_set • Clear the whole thing with FD_ZERO • Add each descriptor you want to watch using FD_SET • Call select • when select returns, use FD_ISSET to see if I/O is possible on each descriptor CPE 401/601 Lecture 12 : I/O Multiplexing
System Calls and Errors • In general, systems calls return a negative number to indicate an error • We often want to find out what error • Servers generally add this information to a log • Clients generally provide some information to the user CPE 401/601 Lecture 12 : Error Handling
What is fatal? • How do you know what should be a fatal error? • Common sense • If the program can continue – it should • if a server can't create a socket, or can't bind to it's port • there is no sense continuing… CPE 401/601 Lecture 12 : Error Handling
extern int errno; • Whenever an error occurs, system calls set the value of the global variable errno • You can check errno for specific errors • errno is valid only after a system call has returned an error • System calls don't clear errno on success • If you make another system call you may lose the previous value of errno • printf makes a call to write! CPE 401/601 Lecture 12 : Error Handling
General Strategies • Include code to check for errors after every system call • Develop "wrapper functions" that do the checking for you • Develop layers of functions, each hides some of the error-handling details CPE 401/601 Lecture 12 : Error Handling
Wrappers are great! • Wrappers like those used in the text can make code much more readable • There are always situations in which you cannot use the wrappers • Sometimes system calls are "interrupted" (EINTR) • this is not always a fatal error ! CPE 401/601 Lecture 12 : Error Handling
Another approach • Instead of simple wrapper functions, you might develop a layered system • The idea is to "hide" the sockaddr and error handling details behind a few custom functions: • int tcp_client(char *server, int port); • int tcp_server(int port); CPE 401/601 Lecture 12 : Error Handling
Layers and Code Re-use • Developing general functions that might be re-used in other programs is obviously "a good thing" • Layering is beneficial even if the code is not intended to be re-used: • hide error-handling from "high-level" code • hide other details • often makes debugging easier CPE 401/601 Lecture 12 : Error Handling
The Best Approach to handling errors • There is no best approach • Do what works for you • Make sure you check all system calls for errors! • Not checking can lead to security problems! • Not checking can lead to bad grades on assignments! CPE 401/601 Lecture 12 : Error Handling
Lecture 13Client/Server Programming CPE 401 / 601 Computer Network Systems slides are modified from Dave Hollinger slides are modified from Dave Hollinger
Issues in Client/Server Programming • Identifying the Server • Looking up an IP address • Looking up a well known port name • Specifying a local IP address • UDP/TCP client design CPE 401/601 Lecture 13 : Client/Server Issues
Identifying the Server • Options: • hard-coded into the client program • require that the user identify the server • read from a configuration file • use a separate protocol/network service to lookup the identity of the server. CPE 401/601 Lecture 13 : Client/Server Issues
Identifying a TCP/IP server • Need an IP address, protocol and port • We often use host names instead of IP addresses • usually the protocol is not specified by the user • UDP vs. TCP • often the port is not specified by the user CPE 401/601 Lecture 13 : Client/Server Issues
Services and Ports • Many services are available via “well known” addresses (names) • There is a mapping of service names to port numbers: struct *servent getservbyname( char *service, char *protocol ); • servent->s_port is the port number in network byte order CPE 401/601 Lecture 13 : Client/Server Issues
Specifying a Local Address • When a client creates and binds a socket, it must specify a local port and IP address • Typically clients don’t care what port it is on: haddr->port = htons(0); give me any available port ! CPE 401/601 Lecture 13 : Client/Server Issues
Local IP address • A client can also ask the operating system to take care of specifying the local IP address: haddr->sin_addr.s_addr= htonl(INADDR_ANY); Give me the appropriate address CPE 401/601 Lecture 13 : Client/Server Issues
UDP Client Design • Establish server address (IP and port) • Allocate a socket • Specify that any valid local port and IP address can be used • Communicate with server (send, recv) • Close the socket CPE 401/601 Lecture 13 : Client/Server Issues
Connected mode UDP • A UDP client can call connect() to establish the address of the server • The UDP client can then use read() and write() or send() and recv() • A UDP client using a connected mode socket can only talk to one server • using the connected-mode socket CPE 401/601 Lecture 13 : Client/Server Issues
TCP Client Design • Establish server address (IP and port) • Allocate a socket • Specify that any valid local port and IP address can be used • Call connect() • Communicate with server (read, write) • Close the connection CPE 401/601 Lecture 13 : Client/Server Issues
Closing a TCP socket • Many TCP based application protocols support • multiple requests and/or • variable length requests over a single TCP connection • How does the server known when the client is done ? • and it is OK to close the socket ? CPE 401/601 Lecture 13 : Client/Server Issues
Partial Close • One solution is for the client to shut down only it’s writing end of the socket • shutdown() system call provides this function shutdown(int s, int direction); • direction can be 0 to close the reading end or 1 to close the writing end • shutdown sends info to the other process! CPE 401/601 Lecture 13 : Client/Server Issues
TCP sockets programming • Common problem areas: • null termination of strings • reads don’t correspond to writes • synchronization (including close()) • ambiguous protocol CPE 401/601 Lecture 13 : Client/Server Issues
TCP Reads • Each call to read() on a TCP socket returns any available data • up to a maximum • TCP buffers data at both ends of the connection • You must be prepared to accept data 1 byte at a time from a TCP socket! CPE 401/601 Lecture 13 : Client/Server Issues
Server Design Concurrent Large or variable size requests Harder to program Typically uses more system resources Iterative Small, fixed size requests Easy to program CPE 401/601 Lecture 13 : Client/Server Issues
Server Design Connection-Oriented EASY TO PROGRAM transport protocol handles the tough stuff. requires separate socket for each connection. Connectionless less overhead no limitation on number of clients CPE 401/601 Lecture 13 : Client/Server Issues
Server Design Iterative Connectionless Iterative Connection-Oriented Concurrent Connectionless Concurrent Connection-Oriented CPE 401/601 Lecture 13 : Client/Server Issues
Statelessness • State: Information that a server maintains about the status of ongoing client interactions • Connectionless servers that keep state information must be designed carefully! Messages can be duplicated! CPE 401/601 Lecture 13 : Client/Server Issues
The Dangers of Statefullness • Clients can go down at any time • Client hosts can reboot many times • The network can lose messages • The network can duplicate messages CPE 401/601 Lecture 13 : Client/Server Issues
Concurrent Server Design Alternatives • One child per client • Spawn one thread per client • Preforking multiple processes • Prethreaded Server CPE 401/601 Lecture 13 : Client/Server Issues
One child per client • Traditional Unix server: • TCP: after call to accept(), call fork() • UDP: after recvfrom(), call fork() • Each process needs only a few sockets • Small requests can be serviced in a small amount of time • Parent process needs to clean up after children!!!! • call wait() CPE 401/601 Lecture 13 : Client/Server Issues
One thread per client • Almost like using fork • call pthread_create instead • Using threads makes it easier to have sibling processes share information • less overhead • Sharing information must be done carefully • use pthread_mutex CPE 401/601 Lecture 13 : Client/Server Issues
Prefork()’d Server • Creating a new process for each client is expensive • We can create a bunch of processes, each of which can take care of a client • Each child process is an iterative server CPE 401/601 Lecture 13 : Client/Server Issues
Prefork()’d TCP Server • Initial process creates socket and binds to well known address. • Process now calls fork() a bunch of times • All children call accept() • The next incoming connection will be handed to one child CPE 401/601 Lecture 13 : Client/Server Issues
Preforking • Having too many preforked children can be bad • Using dynamic process allocation instead of a hard-coded number of children can avoid problems • Parent process just manages the children • doesn’t worry about clients CPE 401/601 Lecture 13 : Client/Server Issues
Sockets library vs. system call • A preforked TCP server won’t always work if sockets is not part of the kernel • calling accept() is a library call, not an atomic operation • We can get around this by making sure only one child calls accept() at a time using some locking scheme CPE 401/601 Lecture 13 : Client/Server Issues
Prethreaded Server • Same benefits as preforking • Can also have the main thread do all the calls to accept() • and hand off each client to an existing thread CPE 401/601 Lecture 13 : Client/Server Issues