Socket bind connect example
The protocol layer outputs data to the interface using the respective interface queues. The socket system call creates a new socket by assigning a new descriptor.
The new descriptor is returned to the calling process. Any subsequent system calls are identified with the created socket. The socket system call also assigns the protocol to the created socket descriptor. The domain , type , and protocol argument values specify the family, type, and protocol to assign to the created socket.
Figure 3 shows the call sequence. Once the arguments are retrieved from the process, the socket function calls the socreate function. The socreate function finds the pointer to the protocol switch protsw structure, depending on the arguments specified by the process. The socreate function then allocates a new socket structure.
The Internet control block also has a pointer pointing to the TCP control block. For more detailed information on Internet control block and TCP control block structures, see the Related topics section. The bind system call associates a local network transport address with a socket. For a client process, it is not mandatory to issue a bind call.
The kernel takes care of doing an implicit binding when the client process issues the connect system call. It is often necessary for a server process to issue an explicit bind request before it can accept connections or start communication with clients. Else implicit binding happens. In the case of explicit binding, checks are performed on the IP address being bound, and the socket options are set accordingly.
The listen call indicates to the protocol that the server process is ready to accept any new incoming connections on the socket. There is a limit on the number of connections that can be queued up, after which any further connection requests are ignored.
The listen system call calls solisten with the socket descriptor and backlog values specified in the listen call. Normally, all the server processes listen on a well-known port number. Figure 5 shows the call sequence for listen. The accept system call is a blocking call that waits for incoming connections. Once a connection request is processed, a new socket descriptor is returned by accept. This new socket is connected to the client and the other socket s remains in LISTEN state to accept further connections.
The accept call first validates the arguments and waits for a connection request to arrive. Until then, the function blocks in a while loop. Once a new connection arrives, the protocol layer wakes up the server process. Accept then checks for any socket errors that might have occurred when it was blocking.
If there were any socket errors, the function returns, and it proceeds further by picking up the new connection from the queue and calls soaccept. The connect system call is normally called by the client process to connect to the server process.
If the client process has not explicitly issued a bind system call before initiating the connection, implicit binding on the local socket is taken care of by the stack. The connect system call copies the foreign address the address to which the connection request needs to be sent from the process to the kernel and calls soconnect.
Figure 8 , Figure 9 , and Figure 10 show the call sequence when the client issues connect , and the server issues accept to initiate and establish a TCP connection. As shown in Figure 9 below, the soconnect now returns to the connect function and sleeps. The interface on the destination the server receives the incoming SYN packet, places it on the ipintrq queue, and raises a software interrupt. The packet is now processed and soisconnected is called, which wakes up the connect call.
The socket state on the client side now is established. This function removes the socket from the incomplete socket queue and puts it into the completed socket queue.
Wakeup is then called to wake up the accept call. The socket on the server side now is established. The shutdown system call closes either one or both ends of the connection. Or to put it another way, as the designer, you will have to decide what the rules of etiquette are for a conversation.
Normally, the connect ing socket starts the conversation, by sending in a request, or perhaps a signon. Now there are two sets of verbs to use for communication. You can use send and recv , or you can transform your client socket into a file-like beast and use read and write. The latter is the way Java presents its sockets. Without a flush in there, you may wait forever for the reply, because the request may still be in your output buffer. Now we come to the major stumbling block of sockets - send and recv operate on the network buffers.
They do not necessarily handle all the bytes you hand them or expect from them , because their major focus is handling the network buffers. In general, they return when the associated network buffers have been filled send or emptied recv. They then tell you how many bytes they handled. It is your responsibility to call them again until your message has been completely dealt with.
When a recv returns 0 bytes, it means the other side has closed or is in the process of closing the connection. You will not receive any more data on this connection. A protocol like HTTP uses a socket for only one transfer.
The client sends a request, then reads a reply. The socket is discarded. This means that a client can detect the end of the reply by receiving 0 bytes. But if you plan to reuse your socket for further transfers, you need to realize that there is no EOT on a socket. The choice is entirely yours, but some ways are righter than others. The easiest enhancement is to make the first character of the message an indicator of message type, and have the type determine the length.
Now you have two recv s - the first to get at least that first character so you can look up the length, and the second in a loop to get the rest. One complication to be aware of: Prefixing the message with its length say, as 5 numeric characters gets more complex, because believe it or not , you may not get all 5 characters in one recv.
And despite having read this, you will eventually get bit by it! In the interests of space, building your character, and preserving my competitive position , these enhancements are left as an exercise for the reader.
Lets move on to cleaning up. It is perfectly possible to send binary data over a socket. The major problem is that not all machines use the same formats for binary data. For example, a Motorola chip will represent a 16 bit integer with the value 1 as the two hex bytes 00 Intel and DEC, however, are byte-reversed - that same 1 is 01 Where network order is host order, these do nothing, but where the machine is byte-reversed, these swap the bytes around appropriately.
In these days of 32 bit machines, the ascii representation of binary data is frequently smaller than the binary representation. The shutdown is an advisory to the socket at the other end. Most socket libraries, however, are so used to programmers neglecting to use this piece of etiquette that normally a close is the same as shutdown ; close.
So in most situations, an explicit shutdown is not needed. One way to use shutdown effectively is in an HTTP-like exchange. The client sends a request and then does a shutdown 1. It can assume it has the complete request.
The server sends a reply. If the send completes successfully then, indeed, the client was still receiving. But relying on this is a very bad habit. Probably the worst thing about using blocking sockets is what happens when the other side comes down hard without doing a close.
Your socket is likely to hang. Do not try to kill the thread - part of the reason that threads are more efficient than processes is that they avoid the overhead associated with the automatic recycling of resources. In other words, if you do manage to kill the thread, your whole process is likely to be screwed up. In Python, you use socket. You do this after creating the socket, but before using it. The major mechanical difference is that send , recv , connect and accept can return without having done anything.
You have of course a number of choices. You can check return code and error codes and generally drive yourself crazy. Your app will grow large, buggy and suck CPU.