《UNIX网络编程——Socket Networking API》(3rd,Vol1)读书笔记(3)

(Still Under Editing...Please wait for several days....


Part II :Elementary Sockets


(从这章起开始细致的介绍核心的socket API编程内容)

Chapter 3 :Sockets Introduction


3.1 Intro

(这章基本只介绍socket(狭义)这一函数接口,又第一章的简单例子我们已经知道主要是需要确定IP地址与端口,于是这一章就围绕着这一点展开)。

We begin with socket address structures, which will be found in almost every example in the text. These structures can be passed in two directions: from the process to the kernel, and from the kernel to the process. The latter case is an example of a value-result argument, and we will encounter other examples of these arguments throughout the text.

3.2 Socket Address Structures

     Most socket functions require a pointer to a socket address structure as an argument. Each supported protocol suite defines its own socket address structure.The names of these structures begin with sockaddr_ and end with a unique suffix for each protocol suite.

IPv4版本: is named sockaddr_in and is defined by including the<netinet/in.h> header.


         

  • Not all vendors support a length field for socket address structures and the POSIX specification does not require this member. 

           

  • Even if the length field is present, we need never set it and need never examine it, unless we are dealing with routing sockets 

        (*     The four socket functions that pass a socket address structure from the process to the kernel,bind,connect,sendto, andsendmsg, all go through thesockargs function in a Berkeley-derived implementation (p. 452 of TCPv2). This function copies the socket address structure from the process and explicitly sets itssin_len member to the size of the structure that was passed as an argument to these four functions. The five socket functions that pass a socket address structure from the kernel to the process,accept,recvfrom,recvmsg,getpeername, andgetsockname, all set thesin_len member before returning to the process. )

  • The POSIX specification requires only three members in the structure:sin_family,sin_addr, andsin_port.

  • The in_addr_t datatype must be an unsigned integer type of at least 32 bits,in_port_t must be an unsigned integer type of at least 16 bits, andsa_family_t can be any unsigned integer type. 

  • Both the IPv4 address and the TCP or UDP port number are always stored in the structure in network byte order. We must be cognizant of this when using these members.

  • The 32-bit IPv4 address can be accessed in two different ways. For example, ifserv is defined as an Internet socket address structure, thenserv.sin_addr references the 32-bit IPv4 address as anin_addr structure, whileserv.sin_addr.s_addr references the same 32-bit IPv4 address as anin_addr_t (typically an unsigned 32-bit integer)

  • The sin_zero member is unused, but we always set it to 0 when filling in one of these structures. By convention, we always set the entire structure to 0 before filling it in, not just thesin_zero member.

  • 本地控制之用。Socket address structures are used only on a given host: The structure itself is not communicated between different hosts,although certain fields (e.g., the IP address and port) are used for communication.



    此外还要注意我们在将Socket Address作为参数传递给相关函数时,由于历史兼容性原因,我们还需要将其显式cast为struct sockaddr型的结构体指针。如

    int bind(int, struct sockaddr *, socklen_t);
    

         This requires that any calls to these functions must cast the pointer to the protocol-specific socket address structure to be a pointer to a generic socket address structure      

       From an application programmer's point of view, theonly use of these generic socket address structures is to cast pointers to protocol-specific structures.

3.3 Value-result arguments     

    主要介绍了如果以sockaddr为参数传递到相关的函数中去。

    We mentioned that when a socket address structure is passed to any socket function, it is always passed by reference. That is, a pointer to the structure is passed. The length of the structure is also passed as an argument. But the way in which the length is passed depends on which direction the structure is being passed: from the process to the kernel, or vice versa.

  1. Three functions,bind,connect, andsendto, pass a socket address structure from the process to the kernel. One argument to these three functions is the pointer to the socket address structure and another argument is the integer size of the structure

  1. Four functions,accept,recvfrom,getsockname, andgetpeername, pass a socket address structure from the kernel to the process, the reverse direction from the previous scenario. Two of the arguments to these four functions are the pointer to the socket address structure along with a pointer to an integer containing the size of the structure

           getpeername(unixfd, (SA *) &cli, &len);
      之所以要以指针的方式传递是因为这个变量有两个作用,它既要作为一个值告诉kernel,同时在这条系统调用函数结束后还会返回由kernel修改过的这个值给process。The reason that the size changes from an integer to be a pointer to an integer is because the size is both a value when the function is called (it tells the kernel the size of the structure so that the kernel does not write past the end of the structure when filling it in) and a result when the function returns (it tells the process how much information the kernel actually stored in the structure). This type of argument is called a value-result argument.

3.4 Byte Ordering Functions

      主要介绍了如果由我们自己本机的“人可读”形式的IP地址、端口转换为sockaddr结构所需要的规定低层表达形式。

      不同的系统存储多字节的方式可能是不同的,有的从低地址开始存储,有的从高地址开始存储。little-indian and big-endian方式。

       Unfortunately, there is no standard between these two byte orderings and we encounter systems that use both formats. We refer to the byte ordering used by a given system as the host byte order.

       The sending protocol stack and the receiving protocol stack must agree on the order in which the bytes of these multibyte fields will be transmitted.

      The Internet protocols use big-endian byte ordering for these multibyte integers.

     both history and the POSIX specification say that certain fields in the socket address structures must be maintained in network byte order. Our concern is therefore converting between host byte order and network byte order. We use the following four functions to convert between these two byte orders.

#include <netinet/in.h>

uint16_t htons(uint16_t host16bitvalue) ;

uint32_t htonl(uint32_t host32bitvalue) ;

Both return: value in network byte order

uint16_t ntohs(uint16_t net16bitvalue) ;

uint32_t ntohl(uint32_t net32bitvalue) ;

Both return: value in host byte order


       In the names of these functions,h stands forhost,n stands fornetwork,s stands forshort, and l stands forlong. The terms "short" and "long" are historical artifacts from the Digital VAX implementation of 4.2BSD. We should instead think ofs as a 16-bit value (such as a TCP or UDP port number) and l as a 32-bit value (such as an IPv4 address). Indeed, on the 64-bit Digital Alpha, a long integer occupies 64 bits, yet thehtonl andntohl functions operate on 32-bit values.

When using these functions, we do not care about the actual values (big-endian or little-endian) for the host byte order and the network byte order. What we must do is call the appropriate function to convert a given value between the host and network byte order.


3.5 Byte Manipulation functions

  We need these types of functions when dealing with socket address structures because we need to manipulate fields such as IP addresses, which can contain bytes of 0, but are not C character strings.The functions beginning withstr (for string), defined by including the<string.h> header, deal with null-terminated C character strings.

    The first group of functions, whose names begin withb (for byte), are from 4.2BSD and are still provided by almost any system that supports the socket functions. The second group of functions, whose names begin withmem (for memory), are from the ANSI C standard and are provided with any system that supports an ANSI C library.

#include <strings.h>

void bzero(void *dest,size_tnbytes);

void bcopy(const void *src,void *dest,size_tnbytes);

int bcmp(const void *ptr1,const void *ptr2,size_tnbytes);

bzero sets the specified number of bytes to 0 in the destination. We often use this function to initialize a socket address structure to 0. 

The following functions are the ANSI C functions:

#include <string.h>

void *memset(void *dest,intc,size_tlen);

void *memcpy(void *dest,const void *src,size_tnbytes);

int memcmp(const void *ptr1,const void *ptr2,size_tnbytes);

Returns: 0 if equal, <0 or >0 if unequal (see text)


memset sets the specified number of bytes to the valuec in the destination.


3.6 inet_aton等转换函数

 

We will describe two groups of address conversion functions in this section and the next. They convert Internet addresses between ASCII strings (what humans prefer to use) and network byte ordered binary values (values that are stored in socket address structures).

  1. inet_aton,inet_ntoa, andinet_addr convert an IPv4 address from a dotted-decimal string (e.g.,"206.168.112.96") to its 32-bit network byte ordered binary value. You will probably encounter these functions in lots of existing code.

  1. The newer functions,inet_pton andinet_ntop, handle both IPv4 and IPv6 addresses. We describe these two functions in the next section and use them throughout the text.

#include <arpa/inet.h>

int inet_aton(const char *strptr,struct in_addr *addrptr);

Returns: 1 if string was valid, 0 on error

in_addr_t inet_addr(const char *strptr);

Returns: 32-bit binary network byte ordered IPv4 address; INADDR_NONE if error

char *inet_ntoa(struct in_addr inaddr);

Returns: pointer to dotted-decimal string


The first of these,inet_aton, converts the C character string pointed to bystrptr into its 32-bit binary network byte ordered value, which is stored through the pointeraddrptr. If successful, 1 is returned; otherwise, 0 is returned.

inet_addr does the same conversion, returning the 32-bit binary network byte ordered value as the return value. 

Today,inet_addr is deprecated and any new code should useinet_aton instead.

The inet_ntoa function converts a 32-bit binary network byte ordered IPv4 address into its corresponding dotted-decimal string. 

3.7 inet_pton and inet_ntop 函数

#include <arpa/inet.h>

int inet_pton(int family,const char *strptr,void *addrptr);

Returns: 1 if OK, 0 if input not a valid presentation format, -1 on error

const char *inet_ntop(int family,const void *addrptr,char *strptr,size_tlen);

Returns: pointer to result if OK, NULL on error

for IPv4:

struct sockaddr_in   addr;

inet_ntop(AF_INET, &addr.sin_addr, str, sizeof(str));
 

for IPv4

These two functions are new with IPv6 and work with both IPv4 and IPv6 addresses. We use these two functions throughout the text. The letters "p" and "n" stand forpresentation and numeric. The presentation format for an address is often an ASCII string and the numeric format is the binary value that goes into a socket address structure.

3.8、3.9略

这部分为作者对一些库函数的进一步封装。

3.10 Summary

Socket address structures are an integral part of every network program. We allocate them, fill them in, and pass pointers to them to various socket functions. Sometimes we pass a pointer to one of these structures to a socket function and it fills in the contents. We always pass these structures by reference (that is, we pass a pointer to the structure, not the structure itself), and we always pass the size of the structure as another argument. When a socket function fills in a structure, the length is also passed by reference, so that its value can be updated by the function. We call these value-result arguments.

Socket address structures are self-defining because they always begin with a field (the "family") that identifies the address family contained in the structure. Newer implementations that support variable-length socket address structures also contain a length field at the beginning, which contains the length of the entire structure.

The two functions that convert IP addresses between presentation format (what we write, such as ASCII characters) and numeric format (what goes into a socket address structure) areinet_pton and inet_ntop. Although we will use these two functions in the coming chapters, they are protocol-dependent. A better technique is to manipulate socket address structures as opaque objects, knowing just the pointer to the structure and its size. We used this method to develop a set of sock_ functions that helped to make our programs protocol-independent. We will complete the development of our protocol-independent tools inChapter 11 with the getaddrinfo andgetnameinfo functions.

chapter 4 Elementary TCP sockets

4.1  Intro

典型的C/S交互流程:

4.2 socket Function

#include <sys/socket.h>

int socket (int family,inttype,intprotocol);

Returns: non-negative descriptor if OK, -1 on error

AF_xxxVersusPF_xxx

The "AF_" prefix stands for "address family" and the "PF_" prefix stands for "protocol family." Historically, the intent was that a single protocol family might support multiple address families and that the PF_ value was used to create the socket and theAF_ value was used in socket address structures. But in actuality,a protocol family supporting multiple address families has never been supported and the<sys/socket.h> header defines thePF_ value for a given protocol to be equal to theAF_ value for that protocol.While there is no guarantee that this equality between the two will always be true, should anyone change this for existing protocols, lots of existing code would break. To conform to existing coding practice,we use only theAF_ constants in this text, although youmay encounter thePF_ value, mainly in calls tosocket.

4.3  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_taddrlen);

Returns: 0 if OK, -1 on error

sockfd is a socket descriptor returned by thesocket function. The second and third arguments are a pointer to a socket address structure and its size.

The socket address structure must contain the IP address and port number of the server.

The client does not have to callbind (which we will describe in the next section) before callingconnect: the kernel will choose both an ephemeral port and the source IP address if necessary.

     If connect fails, the socket is no longer usable and must be closed. We cannot callconnect again on the socket.we will see that when we callconnect in a loop, trying each IP address for a given host until one works, each timeconnect fails, we mustclose the socket descriptor and callsocket again.

4.4 bind function

The bind function assigns a local protocol address to a socket. With the Internet protocols, the protocol address is the combination of either a 32-bit IPv4 address or a 128-bit IPv6 address, along with a 16-bit TCP or UDP port number.

#include <sys/socket.h>

int bind (int sockfd,const struct sockaddr *myaddr,socklen_taddrlen);

Returns: 0 if OK,-1 on error

     The second argument is a pointer to a protocol-specific address, and the third argument is the size of this address structure. With TCP, callingbind lets us specify a port number, an IP address, both, or neither.

  • Servers bind their well-known port when they start. but it is rare for a TCP server to let the kernel choose an ephemeral port, since servers are known by their well-known port.

  • A process canbind a specific IP address to its socket. The IP address must belong to an interface on the host. For a TCP client, this assigns the source IP address(从自身的网卡IP中选一个IP) that will be used for IP datagrams sent on the socket. For a TCP server, this restricts the socket to receive incoming client connections destined only to that IP address.

    • 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, based on the outgoing interface that is used, which in turn is based on the route required to reach the server 

    • If a TCP server does not bind an IP address to its socket, the kernel uses the destination IP address of the client's SYN as the server's source IP address 

If we specify a port number of 0, the kernel chooses an ephemeral port whenbind is called. But if we specify a wildcard IP address, the kernel does not choose the local IP address until either the socket is connected (TCP) or a datagram is sent on the socket (UDP).

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

4.5 listen function

(*从这部分开始,接下来的几节讲的非常的好!内容对于真正的理解这一过程也非常的关键,所以基本上对于原书的内容难以割爱,去之一分都觉得不合适,所以下次复习时在这一部分仍然最好是回顾原书!*)

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

  1. When a socket is created by thesocket function, it is assumed to be an active socket, that is, a client socket that will issue aconnect.Thelisten 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 tolisten moves the socket from the CLOSED state to the LISTEN state.

  2. The second argument to this function specifies themaximum number of connections the kernel should queue for this socket.

#include <sys/socket.h>

#int listen (int sockfd,intbacklog);

Returns: 0 if OK, -1 on error

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

  1. 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 an entry is created on the incomplete queue, the parameters from the listen socket are copied over to the newly created connection. The connection creation mechanism is completely automatic; the server process is not involved.

       When a SYN arrives from a client, TCP creates a new entry on the incomplete queue and then responds with the second segment of the three-way handshake: the server's SYN with an ACK of the client's SYN.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, which we will describe in the next section, 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.

4.6 accept Function

accept is called by a TCP server to return the next completed connection from the front of the completed connection queue .If the completed connection queue is empty, the process is put to sleep (assuming the default of a blocking socket).

#include <sys/socket.h>

int accept (int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen);

Returns: non-negative descriptor if OK, -1 on error

The cliaddr and addrlen arguments are used to return the protocol address of the connected peer process (the client). 

addrlen is a value-result argument : Before the call, we set the integer value referenced by *addrlen to the size of the socket address structure pointed to by cliaddr; on return, this integer value contains the actual number of bytes stored by the kernel in the socket address structure.

If accept is successful, its return value is a brand-new descriptor automatically created by the kernel. This new descriptor refers to the TCP connection with the client. When discussingaccept, we call the first argument to accept thelistening socket(the descriptor created bysocket and then used as the first argument to bothbind andlisten), and we call the return value from accept theconnected socket.It is important to differentiate between these two sockets. 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 isaccepted (i.e., for which the TCP three-way handshake completes). When the server is finished serving a given client, the connected socket is closed.

This function returns up to three values: an integer return code that is either a new socket descriptor or an error indication, the protocol address of the client process (through thecliaddr pointer), and the size of this address (through theaddrlen pointer). If we are not interested in having the protocol address of the client returned, we set bothcliaddr and addrlen to null pointers.

 Our server must run withsuperuser privileges tobind the reserved port of 13. If we do not have superuser privileges, the call tobind will fail

4.7 fork and exec functions

(fork函数用来生成一个新的进程,而exec则是将当前的进程转变为(control流变化)另一个新的任务进程。)

The fork function (including the variants of it provided by some systems) is the only way in Unix to create a new process.

#include <unistd.h>

pid_t fork(void);

Returns: 0 in child, process ID of child in parent, -1 on error

     If you have never seen this function before, the hard part in understandingfork is thatit is calledonce but it returnstwice.It returns once in the calling process (called the parent) with a return value that is the process ID of the newly created process (the child). It also returns once in the child, with a return value of 0. Hence, the return value tells the process whether it is the parent or the child.

     The reasonfork returns 0 in the child, instead of the parent's process ID, is because a child has only one parent and it can always obtain the parent's process ID by callinggetppid. A parent, on the other hand, can have any number of children, and there is no way to obtain the process IDs of its children. If a parent wants to keep track of the process IDs of all its children, it must record the return values fromfork.

    All descriptors open in the parent before the call tofork are shared with the child afterfork returns.We will see this feature used by network servers: The parent callsaccept and then callsfork. The connected socket is then shared between the parent and child. Normally, the child then reads and writes the connected socket and the parent closes the connected socket.

There are two typical uses offork:

  1. A process makes a copy of itself so that one copy can handle one operation while the other copy does another task. This is typical for network servers. We will see many examples of this later in the text.

  2. A process wants to execute another program.Since the only way to create a new process is by callingfork, the process first callsfork to make a copy of itself, and then one of the copies (typically the child process) callsexec (described next) to replace itself with the new program.This is typical for programs such as shells.

       The only way in which an executable program file on disk can be executed by Unix is for an existing process to call one of the sixexec functions.     exec replaces the current process image with the new program file, and this new program normally starts at themain function. The process ID does not change. We refer to the process that callsexec as thecalling process and the newly executed program as thenew program.

     The differences in the sixexec functions are: (a) whether the program file to execute is specified by afilename or apathname; (b) whether the arguments to the new program are listed one by one or referenced through an array of pointers; and (c) whether the environment of the calling process is passed to the new program or whether a new environment is specified.

#include <unistd.h>

int execl (const char *pathname,const char *arg0, ... /* (char *) 0 */ );

int execv (const char *pathname,char *constargv[]);

int execle (const char *pathname,const char *arg0, ...

/* (char *) 0, char *constenvp[] */ );

int execve (const char *pathname,char *constargv[], char *constenvp[]);

int execlp (const char *filename,const char *arg0, ... /* (char *) 0 */ );

int execvp (const char *filename,char *constargv[]);

All six return: -1 on error, no return on success

These functions return to the caller only if an error occurs. Otherwise, control passes to the start of the new program, normally themain function.

这六个函数之间的关系如下图所示。Normally, onlyexecve is a system call within the kernel and the other five are library functions that callexecve.

Note the following differences among these six functions:

  1. The three functions in the top row specify each argument string as a separate argument to theexec function, with a null pointer terminating the variable number of arguments. The three functions in the second row have anargv array, containing pointers to the argument strings. Thisargv array must contain a null pointer to specify its end, since a count is not specified.

  2. The two functions in the left column specify afilename argument. This is converted into apathname using the current PATH environment variable. If thefilename argument toexeclp or execvp contains a slash (/) anywhere in the string, thePATH variable is not used. The four functions in the right two columns specify a fully qualifiedpathname argument.

  3. The four functions in the left two columns do not specify an explicit environment pointer. Instead, the current value of the external variableenviron is used for building an environment list that is passed to the new program. The two functions in the right column specify an explicit environment list. Theenvp array of pointers must be terminated by a null pointer.

4.8  Concurrent Servers

when a client request can take longer to service, we do not want to tie up a single server with one client; we want to handle multiple clients at the same time. The simplest way to write a concurrent server under Unix is tofork a child process to handle each client.

a sketch example :

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 */
}

When a connection is established, accept returns, the server callsfork, and the child process services the client (on connfd, the connected socket) and the parent process waits for another connection (onlistenfd, the listening socket). The parent closes the connected socket since the child handles the new client.

we assume that the function doit does whatever is required to service the client. When this function returns, we explicitly close the connected socket in the child. This is not required since the next statement calls exit, and part of process termination is to close all open descriptors by the kernel. Whether to include this explicit call to close or not is a matter of personal programming taste.

Why doesn't theclose of connfd in Figure 4.13 by the parent terminate its connection with the client? To understand what's happening,we must understand that every file or socket has a reference count. The reference count is maintained in the file table entry .This is a count of the number of descriptors that are currently open that refer to this file or socket. after socket returns, the file table entry associated withlistenfd has a reference count of 1. After accept returns, the file table entry associated withconnfd has a reference count of 1. But, after fork returns, both descriptors are shared (i.e., duplicated) between the parent and child, so the file table entries associated with both sockets now have a reference count of 2. Therefore, when the parent closes connfd, it just decrements the reference count from 2 to 1 and that is all. The actual cleanup and de-allocation of the socket does not happen until the reference count reaches 0. This will occur at some time later when the child closes connfd.

4.9 close function

The normal Unixclose 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

The default action of close with a TCP socket is to mark the socket as closed and return to the process immediately. The socket descriptor is no longer usable by the process: It cannot be used as an argument to read or write. But, TCP will try to send any data that is already queued to be sent to the other end, and after this occurs, the normal TCP connection termination sequence takes place .

If we really want to send a FIN on a TCP connection, theshutdown function can be used (Section 6.6) instead ofclose.

We must also be aware of what happens in our concurrent server if the parent does not callclose 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 nevercloses the connected socket. This will prevent TCP's connection termination sequence from occurring, and the connection will remain open.

4.10 get sockname and getpeername function

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 bylocaladdr or peeraddr.

  • In a TCP server that binds the wildcard IP address (Figure 1.9), once a connection is established with a client (accept returns successfully), the server can callgetsockname to obtain the local IP address assigned to the connection. The socket descriptor argument in this call must be that of the connected socket, and not the listening socket.

  • When a server is execed by the process that calls accept, the only way the server can obtain the identity of the client is to callgetpeername. This is what happens whenever inetd (Section 13.5)forks and execs a TCP server. inetd calls accept (top left box) and two values are returned: the connected socket descriptor,connfd, is the return value of the function, and the small box we label "peer's address" (an Internet socket address structure) contains the IP address and port number of the client.fork is called and a child of inetd is created. Since the child starts with a copy of the parent's memory image, the socket address structure is available to the child, as is the connected socket descriptor (since the descriptors are shared between the parent and child). But when the child execs the real server (say the Telnet server that we show),the memory image of the child is replaced with the new program file for the Telnet server (i.e., the socket address structure containing the peer's address is lost), and the connected socket descriptor remains open across the exec. One of the first function calls performed by the Telnet server isgetpeername to obtain the IP address and port number of the client.


Since the POSIX specification allows a call to getsockname on an unbound socket, this function should work for any open socket descriptor.


chapter 5 TCP Client/Server Example




 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值