************************* Syed Shahzad Ali (ssali) Assignment #4 CS 742 ************************* Q1: In the 3-way handshake, will the server send the acknowledgement to the client before server calls accept? Ans: Select function is normally used with non-blocking I/O to determine when a descriptor is readable or writable. Non-blocking connect let us do other processing while TCP's three-way handshake takes place, instead of being blocked in the call to connect. But the problem arises when different implementation having different ways of indicating that a successful connection is established or not. This leads to some serious porting problems in our code. A good idea could be to use non-blocking concept as used by web client. Web clients opens multiple TCP connection at the same time and reduce the clock time required to fetch numerous files from the server. But sending acknowledgement by server to clients before calling accept happens and server does returns back to client indicating client's local IP address screen. So it is observer that the server does send acknowledgement to the client and when it comes out of the sleep mode return the time back to client. Q2: Describe the procedure to accomplish a non-blocking 'connect' operation? Ans: The conect function is used by a TCP client to establish a connection with a TCP server. int connect(int sockfd,const struct sockaddr *servaddr, socklen_t addrlen); Retunrs:0 if OK, -1 on error In case of a TCP socket, the connect function initiates TCP's three-way handshake. The function returns only when the connection is established or an error occured. Hence this put client into blocking mode. But when a TCP socket is set nonblocking and then connect is called, connect return immediately giving an error condition EINPREGRESS but here TCP three-way handshake continues. After that select detrmines a successful or unsuccessful completion of the connection establishment. Nonblocking connect plays an important role on LAN and WAN where the round-trip time for connect to complete could be hundreds of milliseconds or a few seconds respectively. So during this time instead of waiting for connect to return, we can perform other processing. Another advantage is to have multiple connections at the same time using this approach. Almost every web browser employ this technique. As we know that sockets are non-blocking, if the server to which we are connecting is on the same host, the connection takes place immediately. This should be controlled. A nonblocking connect implementation shows different steps that has to be performed. To set a connect non-blocking first the function fcntl() is called to set the socket as non-blocking. A nonblocking connect then report familiar error called EINPROGRESS, inidcating error that connection has restarted but yet not completed. Then we wait for connection to complete. At this point if the nonblocking connect returned 0, the connection is complete. This only occur when both server and client are on the same host. After this step we initialize the timeval structure and then call select is called and wait for the socket to be ready for either reading or writing. In case of timeout error, select returns 0 and then we should close the socket. Checking for sockets to be readable or writable should be the next step and this is done by adding more error checking routines by calling getsockopt. After everything is checked socket is again turned to be in blocking mode and it then returns. Q3: When socket is in TIME_WAIT state, port number cannot be reused except SO_REUSEADDR option is set. Q3.1: Why this is a problem for server program? MSL is the maximum amount of time that a given IP datagram can live on Ans: Internet. Server has to wait for 2MSL before accepting new connection. This is due to the incarnation problem. If there is a TCP connection between IP1:Port1 and this connection is closed and sometime later we want to create the connection with the same IP:Port pair then server will have to create new socket for this. But it will be confusing for server because TCP prevent old duplicates from a connection from appearing sometime later and hence is a wall against being misinterpreted. 2MSL allows for a packet in one direction to be lost, and another MSL seconds for the reply to be lost. So all old duplicates from previous incarnation are expired. We can restart the client immediately. This is not a problem for the client because client uses a new port everytime to send new data for new connection. It is also evidient from our daytime client program. So even if we restatr the client immediately, it will use another port number for sending data and hence won't create any incarnation on the Internet and will be uniquely identified. Q3.2: A server host has two IPs, IP1 and IP2. Can server program bind one listening socket to address IP1:port and another with IP2:port? Ans: One thing is to remeber that we can't bind a single socket to multiple ports. There has to be multiple sockets, one for each port we want to listen on. Then, we can simply multiplex among them using select().A socket, once created, is bound to a unique port number on the local host. After the socket is bound,it can be accessed by another process by using its address. There are several ways to bind a socket to a unique port. If we create a socket with the address. The socket is bound to the specified port on the local host. If the socket is an os_tcp_connection_server and the host is multihomed (has multiple IP addresses), the socket accepts connections to the specified port via any of its IP addresses. Construct a socket with the address os_socket_address( ip_address, port ) . The socket is bound to the specified port on the host identified by ip_address . Use this method only if you want to bind the socket to one of many IP addresses on a multihomed host. Through the bind system call, a process may specify half of an association, the part, while the connect and accept primitives are used to complete a socket's association by specifying the part. Since the association is created in two steps the association uniqueness requirement indicated previously could be violated unless care is taken. Further, it is unrealistic to expect user programs to always know proper values to use for the local address and local port since a host may reside on multiple networks and the set of allocated port numbers is not directly accessible to a user. To simplify local address binding in the Internet domain the notion of a ``wildcard'' address has been provided. When an address is specified as INADDR_ANY the system interprets the address as ``any valid address''. For example,to bind a specific port number to a socket, but leave the local address unspecified, the following code might be used: #include #include ... struct sockaddr_in sin; ... s = socket(AF_INET, SOCK_STREAM, 0); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(MYPORT); bind(s, (struct sockaddr *) &sin, sizeof (sin)); Sockets with wildcarded local addresses may receive messages directed to the specified port number, and sent to any of the possible addresses assigned to a host. For example, if a host has addresses 192.1.0.4 and 130.10.10.8, and a socket is bound as above, the process will be able to accept connection requests which are addressed to 192.1.0.4 or 130.10.10.8. If a server process wished to only allow hosts on a given network connect to it, it would bind the address of the host on the appropriate network. Q4.1: Why not non-blocking Ans: If the int with the address arg is non-zero, the socket is put into non-blocking mode. Otherwise, the socket is put into blocking mode. The fcntl O_NDELAY and O_NONBLOCK flags (defined in ) are supported by sockets. If the O_NONBLOCK flag is set, the socket is put into POSIX-style non-blocking mode. If the O_NDELAY flag is set, the socket is put into non-blocking mode. Otherwise, the socket is put into blocking mode. Blocking mode is the default. If the O_NONBLOCK or O_NDELAY flag has been set, recv() and send() requests behave accordingly, regardless of any FIOSNBIO requests. If neither the O_NONBLOCK flag nor the O_NDELAY flag has been set, FIOSNBIO requests control the the behavior of recv() and send(). For a blocking send, the synchronization overhead would be the period between the blocking call and the copy over the network. For a non-blocking call, the synchronization overhead is reduced by the amount of time between the non-blocking call and the Wait state , in which useful computation is proceeding. Again, the non-blocking receive will reduce synchronization overhead on the receiving task for the case in which the receive is posted first. There is also a benefit to using a non-blocking receive when the send is posted first. Typically, blocking receives are posted immediately before the message data must be used (to allow the maximum amount of time for the communication to complete). So, the blocking receive would be posted in place of Wait state. This would delay the synchronization with the send call until this later point in the program, and thus increase synchronization overhead on the sending task. Q4.2: if(errno!=E_WOULDBLOCK && errno!=EINTR) Ans: The basic rule is that when a process is blocked in a slow system call and the process catches a signal and the signal handler returns, the system call can return an error of EINTR. For portablility When we write a program that catches signals like most concurrent server does, we must be ready for slow system calls to return EINTR. Q4.3: which implemetation is efficient? Ans: select is efficient since using non-blocking I/O means that you have to poll sockets to see if there is data to be read from them. Polling should usually be avoided since it uses more CPU time than other techniques. Using SIGIO allows applications to do what it does and have the operating system tell it (with a signal) that there is data waiting for it on a socket. The only drawback to this solution is that it can be confusing, and if we are dealing with multiple sockets we will have to do a select() anyway to find out which one(s) is ready to be read. Using select() is great if our application has to accept data from more than one socket at a time since it will block until any one of a number of sockets is ready with data. One other advantage to select() is that we can set a time-out value after which control will be returned to us whether any of the sockets have data for us or not. Q5: When realsize and size may not be equal in a blocking socket. Ans: In write operation the size cannot be be same as passed to function and the one returned by the function. The write() function attempts to write nbyte bytes from the buffer pointed to by buf to the file associated with the open file descriptor, fildes. Upon successful completion, write() returns the number of bytes actually written to the file associated with fildes. This number is never greater than nbyte. Otherwise, -1 is returned. So read calls will return only the amount of data requested, and any remaining in the arriving packet will be discarded.