Unix 网络编程 读书笔记1

第一章:java

C/C++语言提供两种不一样的编程模式:IPL32和PL64。
► IPL32
● 表示integer/pointer/long三种数据类型是32位(4个字节),在这种模式下,提供32
位的地址空间,理论的内存使用限制为4G。
► PL64
● 表示pointer/long两种数据类型是64位(8个字节),提供64位地址空间,使用内存超
过4G(达2^60bytes=1EB)。编程

 more infoabout IPL32 and PL64, please refer to http://www-31.ibm.com/cn/downloadfiles/tsc/faq/cyberclass/aixmig/aixmig.pdf服务器

 第二章:cookie

TCP 链接创建过程:网络

TCP 链接解除过程:并发

TCP 状态和socket 函数调用对应关系:app

深刻理解 listen 和accept 函数socket

1 #include<sys/socket.h>
2 int listen(int sockfd, int backlog);

 

listen函数仅由TCP服务器调用,它作两件事情:tcp

一、当socket函数建立一个套接口时,它被假设为一个主动套装口,也就是说,它是一个将调用connet发起链接的客户套接口。listen函数把一个未链接的套接口转换成一个被动套接口,指示内核应接受指向该套接口的链接请求。根据TCP状态转换图,调用listen致使套接口从CLOSED状态转换到LISTEN状态。函数

二、本函数的第二个参数规定了内核应该为相应套接口排队的最大链接个数。

    为了更好的理解backlog参数,咱们必须认识到内核为任何一个给定的监听套接口维护两个队列:

一、未完成链接队列(incomplete connection queue,每一个这样的SYN分节对应其中一项:已由某个客户发出并到达服务器,而服务器正在等待完成相应的TCP三路握手过程。这些套接口处于SYN_RCVD状态。

二、已完成链接队列(completed connection queue,每一个已完成TCP三路握手过程的客户对应其中一项。这些套接口处于ESTABLISHED状态。

      当来自客户的SYN到达时,TCP在未完成链接队列中建立一个新项,而后响应以三路握手的第二个分节:服务器的SYN响应,其中稍带对客户SYN的ACK(即SYN+ACK)。这一项一直保留在未完成链接队列中,直到三路握手的第三个分节(客户对服务器SYN的ACK)到达或者该项超时为止(曾经源自Berkeley的实现为这些未完成链接的项设置的超时值为75秒)。若是三路握手正常完成,该项就从未完成链接队列移到已完成链接队列的队尾。当进程调用accept时,已完成链接队列中的队头项将返回给进程,或者若是该队列为空,那么进程将被投入睡眠,直到TCP在该队列中放入一项才唤醒它。

3次握手发生在客户端 connect 时 而服务器accept 只是从内核取出能够已完成握手的队列中取出一个。

man listen

 

[root@localhost httpSever]# man listen
LISTEN(2)                  Linux Programmer’s Manual                 LISTEN(2)

 

NAME
       listen - listen for connections on a socket

 

SYNOPSIS
       #include <sys/socket.h>

 

       int listen(int sockfd, int backlog);

 

DESCRIPTION
       To  accept  connections, a socket is first created with socket(2), a willingness to accept incoming connections
       and a queue limit for incoming connections are specified with listen(), and then the connections  are  accepted
       with accept(2).  The listen() call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET.

 

       The backlog parameter defines the maximum length the queue of pending connections may grow to.  If a connection
       request arrives with the queue full the client may receive an error with an indication of ECONNREFUSED  or,  if
       the underlying protocol supports retransmission, the request may be ignored so that retries succeed.

 

NOTES
       The  behaviour  of  the  backlog  parameter  on TCP sockets changed with Linux 2.2.  Now it specifies the queue
       length for completely established sockets waiting to be accepted, instead of the number of  incomplete  connec-
       tion  requests. The maximum length of the queue for incomplete sockets can be set using the tcp_max_syn_backlog
       sysctl.  When syncookies are enabled there is no logical maximum length and this  sysctl  setting  is  ignored.
       See tcp(7) for more information.

 

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

 

ERRORS
       EADDRINUSE
              Another socket is already listening on the same port.

 

       EBADF  The argument sockfd is not a valid descriptor.

 

       ENOTSOCK
              The argument sockfd is not a socket.

 

       EOPNOTSUPP
              The socket is not of a type that supports the listen() operation.

 

CONFORMING TO
       4.4BSD, POSIX.1-2001.  The listen() function call first appeared in 4.2BSD.

 

BUGS
       If the socket is of type AF_INET, and the backlog argument is greater than the constant SOMAXCONN (128 in Linux
       2.0 & 2.2), it is silently truncated to SOMAXCONN.

 

SEE ALSO
       accept(2), bind(2), connect(2), socket(2)

 

BSD Man Page                      1993-07-23                         LISTEN(2)  

 转一篇文章http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520118139252103/

 

在咱们学习网络基础时,传输层的协议有TCP和UDP;

在Linux网络编程中,咱们使用socket API,实现网络通讯。

那么:

        socket API 和 TCP 协议中各个状态是如何对应的呢?咱们能够经过下图来看:

          

在socket系统调用中,如何完成三次握手和四次挥手:

        SOCK_DGRAM,即UDP中的connect操做知识在内核中注册对方机器的IP和PORT信息,并无创建连接的过程,即没有发包,close也不发包)。

       而SOCK_STREAM对应以下:

        connect会完成TCP的三次握手,客户端调用connect后,由内核中的TCP协议完成TCP的三次握手;

        close操做会完成四次挥手。

 

三次握手对应的Berkeley Socket API:

          从图中,能够看出和链接创建相关的API有:connect, listen, accept   3个,connect用在客户端,另外2个用在服务端。

          对于TCP/IP protocol stack来讲,TCP层的tcp_in&tcp_out也参与这个过程。咱们这里只讨论这3个应用层的API干了什么事情。

         (1) connect

                     发送了一个SYN,收到Server的SYN+ACK后,表明链接完成。发送最后一个ACK是protocol stack,tcp_out完成的。

         (2)listen

                    在server这端,准备了一个未完成的链接队列,保存只收到SYN_C的socket结构;

                    还准备了已完成的链接队列,即保存了收到了最后一个ACK的socket结构。

        (3)accept

                   应用进程调用accept的时候,就是去检查上面说的已完成的链接队列,若是队列里有链接,就返回这个链接;

                   若是没有,即空的,blocking方试调用,就睡眠等待;

                                                   nonblocking方式调用,就直接返回,通常一"EWOULDBLOCK“ errno告诉调用者,链接队列是空的。 

 注意:

        在上面的socket API和TCP STATE的对应关系中,TCP协议中,客户端收到Server响应时,可能会有会延迟确认。

        即客户端收到数据后,会阻塞给Server端确认。

        能够在每次收到数据后:

               调用setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){1}, sizeof(int));  快速给Server端确认。

                    

 

 

咱们如何判断有一个创建连接请求或一个关闭连接请求:

      创建连接请求:

一、connect将完成三次握手,accept所监听的fd上,产生读事件,表示有新的连接请求;           

关闭连接请求:

一、close将完成四次挥手,若是有一方关闭sockfd,对方将感知到有读事件,

      若是read读取数据时,返回0,即读取到0个数据,表示有断开连接请求。(在操做系统中已经这么定义) 

    

 

  

关闭连接过程当中的TCP状态和SOCKET处理,及可能出现的问题:

1. TIME_WAIT

 TIME_WAIT 是主动关闭 TCP 链接的那一方出现的状态,系统会在 TIME_WAIT 状态下等待 2MSL(maximum segment lifetime  )后才能释放链接(端口)。一般约合 4 分钟之内。

 进入 TIME_WAIT 状态等待 2MSL 的目的:

          一、确保链接可靠地关闭; 即防止最后一个ACK丢失。

          二、避免产生套接字混淆(同一个端口对应多个套接字)。

(

    意思是,一方close发送了关闭连接请求,对方的应答迟迟到不了(例如网络缘由),致使TIME_WAIT超时,此时这个端口又可用了,

咱们在这个端口上又创建了另一个socket连接。

    若是此时对方的应答到了,怎么处理呢?

            其实这个在TCP层已经处理了,因为有TCP序列号,因此内核TCP层,就会将包丢掉,并给对方发包,让对方将sockfd关闭。

    因此应用层是没有关系的。即咱们用socket API编写程序,就不用处理。

)

注意::

         TIME_WAIT是指操做系统的定时器会等2MSL,而主动关闭sockfd的一方,并不会阻塞。(即应用程序在close时,并不会阻塞)。

         当主动方关闭sockfd后,对方可能不知道这个事件。那么当对方(被动方)写数据,即send时,将会产生错误,即errno为: ECONNRESET。

 

 服务器产生大量 TIME_WAIT 的缘由:(通常咱们不这样开发Server)

  服务器存在大量的主动关闭操做,需关注程序什么时候会执行主动关闭(如批量清理长期空闲的套接字等操做)。

  通常咱们本身写的服务器进行主动断开链接的很少,除非作了空闲超时之类的管理。(TCP短连接是指,客户端发送请求给服务器,客户端收到服务器端的响应后,关闭连接)。

 

 

2. CLOSE_WAIT

 CLOSE_WAIT 是被动关闭 TCP 链接时产生的,

若是收到另外一端关闭链接的请求后,本地(Server端)不关闭相应套接字就会致使本地套接字进入这一状态。

(若是对方关闭了,没有收到关闭连接请求,就是下面的不正常状况)

 

按状态机,我方收到FIN,则由TCP实现发送ACK,所以进入CLOSE_WAIT状态。但若是我方不执行close(),就不能由CLOSE_WAIT迁移到LAST_ACK,则系统中会存在不少CLOSE_WAIT状态的链接。

 

若是存在大量的 CLOSE_WAIT,则说明客户端并发量大,且服务器未能正常感知客户端的退出,也并未及时 close 这些套接字。(若是不及时处理,将会出现没有可用的socket描述符的问题,产生问题的缘由,没有及时close)。

 

正常状况下,一方关闭sockfd,另一方将会有读事件产生, 当recv数据时,若是返回值为0,表示对端已经关闭。此时咱们应该调用close,将对应的sockfd也关闭掉。

 

不正常状况下,一方关闭sockfd,另一方并不知道,(好比在close时,本身断网了,对方就收不到发送的数据包)。此时,若是另一方再向对应的sockfd上写send或读recv数据。

recv时,将会返回0,表示连接已经断开。

send时, 将会产生错误,errno为ECONNRESET。

 

TIME_WAIT状态存在的理由

----------------------------

TCP/IP协议就是这样设计的,是不可避免的。主要有两个缘由:

1)可靠地实现TCP全双工链接的终止

TCP协议在关闭链接的四次握手过程当中,最终的ACK是由主动关闭链接的一端(后面统称A端)发出的,若是这个ACK丢失,对方(后面统称B端)将重发出最终的FIN,所以A端必须维护状态信息(TIME_WAIT)容许它重发最终的ACK。若是A端不维持TIME_WAIT状态,而是处于CLOSED 状态,那么A端将响应RST分节,B端收到后将此分节解释成一个错误(在java中会抛出connection reset的SocketException)。

于是,要实现TCP全双工链接的正常终止,必须处理终止过程当中四个分节任何一个分节的丢失状况,主动关闭链接的A端必须维持TIME_WAIT状态 。

 

2)容许老的重复分节在网络中消逝 

TCP分节可能因为路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个迟到的迷途分节到达时可能会引发问题。在关闭“前一个链接”以后,立刻又从新创建起一个相同的IP和端口之间的“新链接”,“前一个链接”的迷途重复分组在“前一个链接”终止后到达,而被“新链接”收到了。为了不这个状况,TCP协议不容许处于TIME_WAIT状态的链接启动一个新的可用链接,由于TIME_WAIT状态持续2MSL,就能够保证当成功创建一个新TCP链接的时候,来自旧链接重复分组已经在网络中消逝。

 

 

 

转   http://blog.csdn.net/whuslei/article/details/6667471

 

 

创建TCP须要三次握手才能创建,而断开链接则须要四次握手。整个过程以下图所示:

先来看看如何创建链接的。

首先Client端发送链接请求报文,Server段接受链接后回复ACK报文,并为此次链接分配资源。Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP链接就创建了。

那如何断开链接呢?简单的过程以下:

【注意】中断链接端能够是Client端,也能够是Server端。

假设Client端发起中断链接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",可是若是你还有数据没有发送完成,则没必要急着关闭Socket,能够继续发送数据。因此你先发送ACK,"告诉Client端,你的请求我收到了,可是我还没准备好,请继续你等个人消息"。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端肯定数据已发送完成,则向Client端发送FIN报文,"告诉Client端,好了,我这边数据发完了,准备好关闭链接了"。Client端收到FIN报文后,"就知道能够关闭链接了,可是他仍是不相信网络,怕Server端不知道要关闭,因此发送ACK后进入TIME_WAIT状态,若是Server端没有收到ACK则能够重传。“,Server端收到ACK后,"就知道能够断开链接了"。Client端等待了2MSL后依然没有收到回复,则证实Server端已正常关闭,那好,我Client端也能够关闭链接了。Ok,TCP链接就这样关闭了!

整个过程Client端所经历的状态以下:

而Server端所经历的过程以下:转载请注明:blog.csdn.net/whuslei

【注意】 在TIME_WAIT状态中,若是TCP client端最后一次发送的ACK丢失了,它将从新发送。TIME_WAIT状态中所须要的时间是依赖于实现方法的。典型的值为30秒、1分钟和2分钟。等待以后链接正式关闭,而且全部的资源(包括端口号)都被释放。

【问题1】为何链接的时候是三次握手,关闭的时候倒是四次握手?
答:由于当Server端收到Client端的SYN链接请求报文后,能够直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。可是关闭链接时,当Server端收到FIN报文时,极可能并不会当即关闭SOCKET,因此只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端全部的报文都发送完了,我才能发送FIN报文,所以不能一块儿发送。故须要四步握手。

【问题2】为何TIME_WAIT状态须要通过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,咱们能够直接进入CLOSE状态了,可是咱们必须假象网络是不可靠的,有能够最后一个ACK丢失。因此TIME_WAIT状态就是用来重发可能丢失的ACK报文。

 

 

 

 

 

 

 

 

  不少人会问,为何建连接要3次握手,断连接须要4次挥手?

  • 对于建连接的3次握手,主要是要初始化Sequence Number 的初始值。通讯的双方要互相通知对方本身的初始化的Sequence Number(缩写为ISN:Inital Sequence Number)——因此叫SYN,全称Synchronize Sequence Numbers。也就上图中的 x 和 y。这个号要做为之后的数据通讯的序号,以保证应用层接收到的数据不会由于网络上的传输的问题而乱序(TCP会用这个序号来拼接数据)。
    • 对于4次挥手,其实你仔细看是2次,由于TCP是全双工的,因此,发送方和接收方都须要Fin和Ack。只不过,有一方是被动的,因此看上去就成了所谓的4次挥手。若是两边同时断链接,那就会就进入到CLOSING状态,而后到达TIME_WAIT状态。下图是双方同时断链接的示意图(你一样能够对照着TCP状态机看):

相关文章
相关标签/搜索