TCP相关

1.包首部

  1)源端和目的端的端口号客户IP地址、客户端口号、服务器IP地址和服务器端口号的四元组)可唯一确定互联网络中每个TCP连接的双方。

  2)序号用来标识从TCP发端向TCP收端发送的数据字节流,它表示在这个报文段中的的第一个数据字节。如果将字节流看作在两个应用程序间的单向流动,则TCP用序号对每个字节进行计数。序号是32bit的无符号数,序号到达232-1后又从0开始。

  当建立一个新的连接时(或断开连接),序号字段包含由这个主机选择的该连接的初始序号ISN(InitialSequenceNumber)。ISN随时间而变化,因此每个连接都将有不同的ISN。这样做,一方面是为了防止连接失效后SOCKET被重用使得以前残留的包被错误的接受;另一方面是为了防止黑客轻易的知道序列号之后制造tcp序列号攻击。

  3)既然每个传输的字节都被计数,确认序号包含发送确认的一端所期望收到的下一个序号。因此,确认序号应当是上次已成功收到数据字节序号加1。只有ACK标志(下面介绍)为1时确认序号字段才有效。

  发送ACK无需任何代价,因为32bit的确认序号字段和ACK标志一样,总是
TCP首部的一部分。因此,我们看到一旦一个连接建立起来,这个字段总是被设置,ACK标志也总是被设置为1。

  4)首部长度给出首部中32bit字的数目。需要这个值是因为任选字段的长度是可变的。这个字段占4bit,因此TCP最多有60字节的首部。然而,没有任选字段,正常的长度是20字节。

  5)6个标志比特。它们中的多个可同时被设置为1。

  URG紧急指针(urgentpointer)有效
  ACK确认序号有效。acknowledge
  PSH接收方应该尽快将这个报文段交给应用层。push
  RST重建连接。reset
  SYN同步序号用来发起一个连接。synchronization
  FIN发端完成发送任务。finish

  6)TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。窗口大小是一个16bit字段,因而窗口大小最大为65535字节。

  7)检验和覆盖了整个TCP报文段:TCP首部和TCP数据。这是一个强制性的字段,一定是由发端计算和存储,并由收端进行验证。TCP检验和的计算和UDP检验和的计算相似。

  8)只有当URG标志置1时紧急指针才有效。紧急指针是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。
TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。

  9)最常见的可选字段是最长报文大小,又称为MSS(MaximumSegmentSize)。每个连接方通常都在通信的第一个报文段(为建立连接而设置SYN标志的那个段)中指明这个选项。它指明本端所能接收的最大长度的报文段。

2.三次握手

TCP状态转换机说明 - 伟子 - 伟甲天下

  1)请求端(通常称为客户)发送一个 SYN 报文段( SYN 为 1 )指明客户打算连接的服务器的端口,以及初始顺序号( ISN )。

      2)服务器发回包含服务器的初始顺序号的 SYN 报文段( SYN 为 1 )作为应答(还有服务器顺序号)。同时,将确认号设置为客户的 ISN 加 1 以对客户的 SYN 报文段进行确认( ACK 也为 1 )。

      3)客户必须将确认号设置为服务器的 ISN 加 1 以对服务器的 SYN 报文段进行确认( ACK 为 1 ),该报文通知目的主机双方已完成连接建立。

3.关闭连接

TCP状态转换机说明 - 伟子 - 伟甲天下

  因为 TCP 的半关闭( half-close ),所以才要4次握手才能关闭TCP(图上有错,是4次)。由于一个 TCP 连接是全双工(即数据在两个方向上能同时传递),因此每个方向必须单独地进行关闭。关闭的原则就是当一方完成它的数据发送任务后就能发送一个 FIN 来终止这个方向连接。当一端收到一个 FIN ,它必须通知应用层另一端已经终止了那个方向的数据传送。发送 FIN 通常是应用层进行关闭的结果。

从一方的 TCP 来说,连接的关闭有三种情况:

  • 本方启动关闭

  收到本方应用进程的关闭命令后, TCP 在发送完尚未处理的报文段后,发 FIN = 1 的报文段给对方,且 TCP 不再受理本方应用进程的数据发送。在 FIN 以前发送的数据字节,包括 FIN ,都需要对方确认,否则要重传。注意 FIN 也占一个顺序号。一旦收到对方对 FIN 的确认以及对方的 FIN 报文段,本方 TCP 就对该 FIN 进行确认,在等待一段时间,然后关闭连接。等待是为了防止本方的确认报文丢失,避免对方的重传报文干扰新的连接。

  • 对方启动关闭

  当 TCP 收到对方发来的 FIN 报文时,1.发 ACK 确认此 FIN 报文,并通知应用进程连接正在关闭。应用进程将以关闭命令响应。 2.TCP 在发送完尚未处理的报文段后,发一个 FIN 报文给对方 TCP ,然后等待对方对 FIN 的确认,收到确认后关闭连接。若对方的确认未及时到达,在等待一段时间后也关闭连接。

  • 双方同时启动关闭

  连接双方的应用进程同时发关闭命令,则双方 TCP 在发送完尚未处理的报文段后,发送 FIN 报文。各方 TCP 在 FIN 前所发报文都得到确认后,发 ACK 确认它收到的 FIN 。各方在收到对方对 FIN 的确认后,同样等待一段时间再关闭连接。这称之为同时关闭( simultaneous close )。

  当关闭连接时,read函数会返回-1!。

4.TCP状态机

TCP状态转换机说明 - 伟子 - 伟甲天下

 

表 3-2 TCP 状态表

 

状 态

描 述

CLOSED

关闭状态,没有连接活动或正在进行

LISTEN

监听状态,服务器正在等待连接进入

SYN RCVD

收到一个连接请求,尚未确认

SYN SENT

已经发出连接请求,等待确认

ESTABLISHED

连接建立,正常数据传输状态

FIN WAIT 1

(主动关闭)已经发送关闭请求,等待确认

FIN WAIT 2

(主动关闭)收到对方关闭确认,等待对方关闭请求

TIMED WAIT

完成双向关闭,等待所有分组死掉

CLOSING

双方同时尝试关闭,等待对方确认

CLOSE WAIT

(被动关闭)收到对方关闭请求,已经确认

LAST ACK

(被动关闭)等待最后一个关闭确认,并等待所有分组死掉

 

 

5.坚持定时器

  如果一个确认丢失了,则双方就有可能因为等待对方而使连接终止:接收方等待接收数据(因为它已经向发送方通告了一个非 0的窗口,但此通告也许丢失),而发送方在等待允许它继续发送数据的窗口更新。为防止这种死锁情况的发生,发送方使用一个坚持定时器 (persist timer)来周期性地向接收方查询,以便发现窗口是否已增大。这些从发送方发出的报文段称为窗口探查 (window  probe)。

  当TCP服务器收到了客户端的0滑动窗口报文的时候,就启动一个定时器来计时,并在定时器溢出的时候向向客户端查询窗口,是否已经增大,如果得到非零的窗口就重新开始发送数据,如果得到0窗口就再开一个新的定时器准备下一次查询。

6.长连接与短连接和保活定时器

  长连接就是Client方与Server方先建立通讯连接,连接建立后不断开。

  短连接就是Client方与Server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。

  保活功能主要为服务器应用提供,服务器应用希望知道客户主机是否崩溃,从而可以代表客户使用资源。如果客户已经消失,使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据,则服务器将应远等待客户端的数据,保活功能就是试图在服务器端检测到这种半开放的连接。

  eg:如果一个给定的连接在两小时内没有任何的动作,则服务器就向客户发一个探测报文段,来查看客户有没有ack。

  长连接:

  Keep-Alive模式,http 1.1中默认启用Keep-Alive,如果加入"Connection: close ",才关闭。目前大部分浏览器都是用http1.1协议,也就是说默认都会发起Keep-Alive的连接请求了,所以是否能完成一个完整的Keep- Alive连接就看服务器设置情况。

  如何判消息内容/长度的大小?

  1、使用消息首部字段Conent-Length
  故名思意,Conent-Length表示实体内容长度,客户端(服务器)可以根据这个值来判断数据是否接收完成。
  2、使用消息首部字段Transfer-Encoding
  当客户端向服务器请求一个静态页面或者一张图片时,服务器可以很清楚的知道内容大小,然后通过Content-length消息首部字段告诉客户端 需要接收多少数据。但是如果是动态页面等时,服务器是不可能预先知道内容大小,这时就可以使用Transfer-Encoding:chunk模式来传输 数据了。即如果要一边产生数据,一边发给客户端,服务器就需要使用"Transfer-Encoding: chunked"这样的方式来代替Content-Length。

7.java TCP

  //创建Socket 客户端对象
  Socket s = new Socket("127.0.0.1",6666);


  //创建ServerSocket 服务器端对象。。
  ServerSocket ss = new ServerSocket(6666);
  //监听服务器连接
  s = ss.accept()();

 

 

参考(转):TCP/IP详解 stevens

 

 

posted on 2013-11-12 18:32  依蓝jslee  阅读(210)  评论(0编辑  收藏  举报

导航