UNP读书笔记--Chapter 4 Elementary TCP Sockets

This chapter describes the elementary socket functions required to write a complete TCP client and server.

'socket' Function

To perform network I/O, the first thing a process must do is call the socket  function, specifying the type of communication protocol desired (TCP using IPv4, UDP using 
IPv6, Unix domain stream protocol, etc.).

#include <sys/socket.h>
int socket (int family, int type, int protocol);
                              Returns: non-negative descriptor if OK, -1 on error
family, often referred to as domain, is one of the types as follows:

   family             Description
AF_INET         IPv4 protocols

AF_INET6       IPv6 protocols

AF_LOCAL     Unix domain protocols

AF_ROUTE    Routing sockets

AF_KEY          Key socket

type of socket for socket function

      type                                    Description

SOCK_STREAM              stream socket

SOCK_DGRAM                datagram socket

SOCK_SEQPACKET       sequenced packet socket

SOCK_RAW                      raw socket

The protocol argument to the socket function should be set to the specific protocol type as follows, or 0 to select the system's default for the given combination of family and type.

    Protocol                            Description

IPPROTO_TCP           TCP transport protocol

IPPROTO_UDP           UDP transport protocol

IPPROTO_SCTP          SCTP transport protocol


'connect' Function

The connect function is used by a TCP client to establish a connection with a TCP server.

#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
                                         Returns: 0 if OK, -1 on error

The socket address structure must contain the IP address and port number of the server.The client does not have to call bind before calling connect:  the  kernel will choose both an ephemeral port and the source IP address if necessary.
In the case of a TCP socket, the  connect  function initiates TCP's three-way handshake.

'bind' Function

The bind function assigns a local protocol address to a socket,and what that protocol address means depends on the protocol.

#include <sys/socket.h>
int bind (int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
                                         Returns: 0 if OK,-1 on error

Normally, a TCP client does not bind an IP address to its socket. The kernel chooses the source IP address when the socket is connected.

Calling bind lets us specify the IP address, the port, both, or neither.

 

With IPv4, the wildcard  address is specified by the constant  INADDR_ANY, whose value is normally 0. This tells the kernel to choose the IP address.

struct sockaddr_in servaddr;
servaddr.sin_addr.s_addr = htonl (INADDR_ANY); /* wildcard */


To obtain the value of the ephemeral port assigned by the kernel, we must call getsockname to return the protocol address.

 'listen' Function

The listen function is called only by a TCP server and it performs two actions: 

1.When a socket is created by the socket  function, it is assumed to be an active socket, that is, a client socket that will issue a connect. The listen function converts an unconnected socket into a passive socket, indicating that the kernel should accept incoming connection requests directed to this socket. In terms of the TCP state transition diagram (Figure 2.4), the call to listen moves the socket from the CLOSED state to the LISTEN state.
2.  The second argument to this function specifies the maximum number of connections the kernel should queue for this socket.

#include <sys/socket.h>
#int listen (int sockfd, int backlog);
                       Returns: 0 if OK, -1 on error

To understand the  backlog  argument, we must realize that for a given listening socket, the kernel maintains two queues:
1.  An incomplete connection queue, which contains an entry for each SYN that has arrived from a client for which the server is awaiting completion of the TCP 
three-way handshake. These sockets are in the SYN_RCVD state .
2.  A completed connection queue, which contains an entry for each client with whom the TCP three-way handshake has completed. These sockets are in the ESTABLISHED state.

When a SYN arrives from a client, TCP creates a new entry on the incomplete queue.This entry will remain on the incomplete queue until the third segment of the three-way handshake arrives (the client's ACK of the server's SYN), or until the entry times out.If the three-way handshake completes normally, the entry moves from the incomplete queue to the end of the completed queue. When the process callsaccept, the first entry on the completed queue is returned to the process, or if the queue is empty, the process is put to sleep until an entry is placed onto the completed queue.
The backlog argument to the listen function has historically specified the maximum value for the sum of both queues.

If the queues are full when a client SYN arrives, TCP ignores the arriving SYN (pp. 930–931 of TCPv2); it does not send an RST. This is because the condition is considered temporary, and the client TCP will retransmit its SYN, hopefully finding room on the queue in the near future. If the server TCP immediately responded with an RST, the client's connect would return an error, forcing the application to handle this condition instead of letting TCP's normal retransmission take over. Also, the client could not differentiate between an RST in response to a SYN meaning "there is no server at this port" versus "there is a server at this port but its queues are full."

'accept' Function

accept is called by a TCP server to return the next completed connection from the front of the completed connection queue.

#include <sys/socket.h>
int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
                       Returns: non-negative descriptor if OK, -1 on error

we call the first argument to accept the listening socket (the descriptor created by socket and then used as the first argument to both bind and listen), and we call the return value from accept the connected socket.A given server normally creates only one listening socket, which then exists for the lifetime of the server. The kernel
creates one connected socket for each client connection that is accepted (i.e., for which the TCP three-way handshake completes). When the server is finished serving
a given client, the connected socket is closed.

'fork' and 'exec' Functions

Normally, the child then reads and writes the connected socket and the parent closes the connected socket.

Concurrent Servers

The simplest way to write a  concurrent server  under Unix is to  fork  a child process to handle each client.

Outline for typical concurrent server
pid_t pid;
int  listenfd, connfd;
listenfd = Socket( ... );
/* fill in sockaddr_in{} with server's well-known port */
Bind(listenfd, ... );
Listen(listenfd, LISTENQ);
for ( ; ; )
{
    connfd = Accept (listenfd, ... ); /* probably blocks */
    if ( (pid = Fork()) == 0)
    {
        Close(listenfd); /* child closes listening socket */
        doit(connfd); /* process the request */
        Close(connfd); /* done with this client */
        exit(0); /* child terminates */
    }
    Close(connfd); /* parent closes connected socket */
}

'close' Function

The normal Unix close function is also used to close a socket and terminate a TCP connection.

#include <unistd.h>
int close (int sockfd);
                         Returns: 0 if OK, -1 on error
If we really want to send a FIN on a TCP connection, the shutdown function can be used instead of  close.
We must also be aware of what happens in our concurrent server if the parent does not call close for each connected socket returned by accept. First, the parent will 
eventually run out of descriptors, as there is usually a limit to the number of descriptors that any process can have open at any time. But more importantly, none of the client connections will be terminated. When the child closes the connected socket, its reference count will go from 2 to 1 and it will remain at 1 since the parent 
never closes the connected socket. This will prevent TCP's connection termination sequence from occurring, and the connection will remain open.

'getsockname' and 'getpeername' Functions

These two functions return either the local protocol address associated with a socket (getsockname) or the foreign protocol address associated with a socket 
(getpeername).

#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
                                  Both return: 0 if OK, -1 on error
Notice that the final argument for both functions is a value-result argument. That is, both functions fill in the socket address structure pointed to by localaddr  or  peeraddr.
Summary

Most TCP servers are concurrent, with the server calling fork for every client connection that it handles, while most UDP servers are iterative. 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值