深入理解TCP协议:三次握手详解

1.什么是三次握手?

TCP协议建立连接时,需要三次发送数据包:

第一次:客户机向服务器端请求建立连接

第二次:服务器收到客户机的请求,发出响应

第三次:客户机收到响应 认为连接建立成功

详细过程:

名词解释:

SYN - 标志位 只有第一次和第二次为1,第三次和其他任何情况都是0

ACK - 标志位 只有第一次不为1,第二,三次和其他任何情况都是1

Sequence Number 顺序号,初始值为随机数

Acknowledgment Number 确认号,下一次对收到的数据顺序号的期望

第一次:

客户机 >>服务器

SYN =1

ACK =0

Sequence Number=X(随机数)

第二次:

SYN =1

ACK =1

Sequence Number=Y(随机数)

Acknowledgment Number=X+1

客户机<<服务器

第三次:

SYN =0

ACK =1

Sequence Number=X+1

Acknowledgment Number=Y+1

客户机 >>服务器

2.为什么要有三次握手?

我们考虑一次和两次握手为什么不行:

考虑

链路1 客户机 >>服务器

链路2 客户机<<服务器

一次握手:

如果链路1故障,客户机仍然会认为连接成功,而服务器不知道连接发生

如果链路2故障,服务器和客户机都会认为连接成功

两次握手:

如果链路2故障,服务器会认为连接成功

接下来考虑三次握手:

如果链路1故障

服务器端收不到第一次握手包,因而不会认为有连接请求,没有误认为连接成功,也不会发送第二次握手包

客户机收不到第二次握手包(服务器端没有发送),没有误认为连接成功

双方都不会误认为连接成功

如果链路2故障

客户机收不到第二次握手包(服务器端发送了但由于链路故障没有收到),没有误认为连接成功,也不会发送第三次握手包

服务器端收不到第三次握手包(客户机没有发送),没有误认为连接成功

双方都不会误认为连接成功

3.捕获一次典型的TCP三次握手:

我们使用wireshark工具

首先 在cmd执行 ping www.baidu.com

这是为了确定目标IP地址,便于设置捕获规则

ip.addr==180.101.49.12

打开www.baidu.com

捕获到

这三个数据包即是TCP三次握手数据包(192.168.3.89是本地IP)

这里有一个问题:为什么Seq的初始值是0而不是一个随机数?

这是wireShark软件本身的特性,显示的不是实际值而是相对值

三次Sequence Number和Acknowledgment Number的真实值(使用十六进制):

第一次(分别是前八位和后八位):

第二次:

第三次:

可以看到符合

X 0

Y X+1

X+1 Y+1的规律

和我们的预期相符

三次数据包的标志位:

第一次:

第二次:

第三次:

可以看到wireshark已经非常贴心的替我们做好了标注

也和我们的预期一致

3.代码追踪和分析:

在之前的实验中,我们知道发出TCP连接请求的函数是__sys_connect

我们分析这个函数的源代码

 1 int __sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen)
 2 {
 3     struct socket *sock;
 4     struct sockaddr_storage address;
 5     int err, fput_needed;
 6     sock = sockfd_lookup_light(fd, &err, &fput_needed);
 7     if (!sock)
 8         goto out;
 9     err = move_addr_to_kernel(uservaddr, addrlen, &address);
10     if (err < 0)
11         goto out_put;
12     err =
13         security_socket_connect(sock, (struct sockaddr *)&address, addrlen);
14     if (err)
15         goto out_put;
16
17     err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen,
18                  sock->file->f_flags);
19 out_put:
20     fput_light(sock->file, fput_needed);
21 out:
22     return err;
23 }

主要的执行过程是

1 err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen,
2                     sock->file->f_flags)

这是一个函数指针,我们通过gdb,发现指向:inet_stream_connect

源代码

 1 int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 2             int addr_len, int flags)
 3 {
 4     int err;
 5
 6     lock_sock(sock->sk);
 7     err = __inet_stream_connect(sock, uaddr, addr_len, flags, 0);
 8     release_sock(sock->sk);
 9     return err;
10 }

发现是对__inet_stream_connect的封装,前面应当是并发控制

继续追踪源代码:

 1 int __inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 2               int addr_len, int flags)
 3 {
 4     struct sock *sk = sock->sk;
 5     int err;
 6     long timeo;
 7
 8     if (addr_len < sizeof(uaddr->sa_family))
 9         return -EINVAL;
10
11     if (uaddr->sa_family == AF_UNSPEC) {
12         err = sk->sk_prot->disconnect(sk, flags);
13         sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;
14         goto out;
15     }
16     switch (sock->state) {
17     default:
18         err = -EINVAL;
19         goto out;
20     case SS_CONNECTED:
21         err = -EISCONN;
22         goto out;
23     case SS_CONNECTING:
24         err = -EALREADY;
25         break;
26     case SS_UNCONNECTED:
27         err = -EISCONN;
28         if (sk->sk_state != TCP_CLOSE)
29             goto out;
30         err = sk->sk_prot->connect(sk, uaddr, addr_len);
31 ...太长了 后面的先省略

 重点是err = sk->sk_prot->connect(sk, uaddr, addr_len);

可以看到这个函数又是通过一个函数指针工作的

err = sk->sk_prot->connect(sk, uaddr, addr_len);

追踪这个函数指针,发现最终指向:tcp_v4_connect

源代码

  1 int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
  2 {
  3     struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
  4     struct inet_sock *inet = inet_sk(sk);
  5     struct tcp_sock *tp = tcp_sk(sk);
  6     __be16 orig_sport, orig_dport;
  7     __be32 daddr, nexthop;
  8     struct flowi4 *fl4;
  9     struct rtable *rt;
 10     int err;
 11     struct ip_options_rcu *inet_opt;
 12     struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;
 13
 14     if (addr_len < sizeof(struct sockaddr_in))
 15         return -EINVAL;
 16
 17     if (usin->sin_family != AF_INET)
 18         return -EAFNOSUPPORT;
 19
 20     nexthop = daddr = usin->sin_addr.s_addr;
 21     inet_opt = rcu_dereference_protected(inet->inet_opt,
 22                          lockdep_sock_is_held(sk));
 23     if (inet_opt && inet_opt->opt.srr) {
 24         if (!daddr)
 25             return -EINVAL;
 26         nexthop = inet_opt->opt.faddr;
 27     }
 28
 29     orig_sport = inet->inet_sport;
 30     orig_dport = usin->sin_port;
 31     fl4 = &inet->cork.fl.u.ip4;
 32     rt = ip_route_connect(fl4, nexthop, inet->inet_saddr,
 33                   RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
 34                   IPPROTO_TCP,
 35                   orig_sport, orig_dport, sk);
 36     if (IS_ERR(rt)) {
 37         err = PTR_ERR(rt);
 38         if (err == -ENETUNREACH)
 39             IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
 40         return err;
 41     }
 42
 43     if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
 44         ip_rt_put(rt);
 45         return -ENETUNREACH;
 46     }
 47
 48     if (!inet_opt || !inet_opt->opt.srr)
 49         daddr = fl4->daddr;
 50
 51     if (!inet->inet_saddr)
 52         inet->inet_saddr = fl4->saddr;
 53     sk_rcv_saddr_set(sk, inet->inet_saddr);
 54
 55     if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) {
 56         /* Reset inherited state */
 57         tp->rx_opt.ts_recent       = 0;
 58         tp->rx_opt.ts_recent_stamp = 0;
 59         if (likely(!tp->repair))
 60             tp->write_seq       = 0;
 61     }
 62
 63     inet->inet_dport = usin->sin_port;
 64     sk_daddr_set(sk, daddr);
 65
 66     inet_csk(sk)->icsk_ext_hdr_len = 0;
 67     if (inet_opt)
 68         inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
 69
 70     tp->rx_opt.mss_clamp = TCP_MSS_DEFAULT;
 71
 72     tcp_set_state(sk, TCP_SYN_SENT);
 73     err = inet_hash_connect(tcp_death_row, sk);
 74     if (err)
 75         goto failure;
 76
 77     sk_set_txhash(sk);
 78
 79     rt = ip_route_newports(fl4, rt, orig_sport, orig_dport,
 80                    inet->inet_sport, inet->inet_dport, sk);
 81     if (IS_ERR(rt)) {
 82         err = PTR_ERR(rt);
 83         rt = NULL;
 84         goto failure;
 85     }
 86
 87     sk->sk_gso_type = SKB_GSO_TCPV4;
 88     sk_setup_caps(sk, &rt->dst);
 89     rt = NULL;
 90
 91     if (likely(!tp->repair)) {
 92         if (!tp->write_seq)
 93             tp->write_seq = secure_tcp_seq(inet->inet_saddr,
 94                                inet->inet_daddr,
 95                                inet->inet_sport,
 96                                usin->sin_port);
 97         tp->tsoffset = secure_tcp_ts_off(sock_net(sk),
 98                          inet->inet_saddr,
 99                          inet->inet_daddr);
100     }
101
102     inet->inet_id = tp->write_seq ^ jiffies;
103
104     if (tcp_fastopen_defer_connect(sk, &err))
105         return err;
106     if (err)
107         goto failure;
108
109     err = tcp_connect(sk);
110
111     if (err)
112         goto failure;
113
114     return 0;
115
116 failure:
117
118     tcp_set_state(sk, TCP_CLOSE);
119     ip_rt_put(rt);
120     sk->sk_route_caps = 0;
121     inet->inet_dport = 0;
122     return err;
123 }

重点在于

72  tcp_set_state(sk, TCP_SYN_SENT)
109 err = tcp_connect(sk);

继续分析

源代码:

 1 void tcp_set_state(struct sock *sk, int state)
 2 {
 3     int oldstate = sk->sk_state;
 4
 5     /* We defined a new enum for TCP states that are exported in BPF
 6      * so as not force the internal TCP states to be frozen. The
 7      * following checks will detect if an internal state value ever
 8      * differs from the BPF value. If this ever happens, then we will
 9      * need to remap the internal value to the BPF value before calling
10      * tcp_call_bpf_2arg.
11      */
12     BUILD_BUG_ON((int)BPF_TCP_ESTABLISHED != (int)TCP_ESTABLISHED);
13     BUILD_BUG_ON((int)BPF_TCP_SYN_SENT != (int)TCP_SYN_SENT);
14     BUILD_BUG_ON((int)BPF_TCP_SYN_RECV != (int)TCP_SYN_RECV);
15     BUILD_BUG_ON((int)BPF_TCP_FIN_WAIT1 != (int)TCP_FIN_WAIT1);
16     BUILD_BUG_ON((int)BPF_TCP_FIN_WAIT2 != (int)TCP_FIN_WAIT2);
17     BUILD_BUG_ON((int)BPF_TCP_TIME_WAIT != (int)TCP_TIME_WAIT);
18     BUILD_BUG_ON((int)BPF_TCP_CLOSE != (int)TCP_CLOSE);
19     BUILD_BUG_ON((int)BPF_TCP_CLOSE_WAIT != (int)TCP_CLOSE_WAIT);
20     BUILD_BUG_ON((int)BPF_TCP_LAST_ACK != (int)TCP_LAST_ACK);
21     BUILD_BUG_ON((int)BPF_TCP_LISTEN != (int)TCP_LISTEN);
22     BUILD_BUG_ON((int)BPF_TCP_CLOSING != (int)TCP_CLOSING);
23     BUILD_BUG_ON((int)BPF_TCP_NEW_SYN_RECV != (int)TCP_NEW_SYN_RECV);
24     BUILD_BUG_ON((int)BPF_TCP_MAX_STATES != (int)TCP_MAX_STATES);
25
26     if (BPF_SOCK_OPS_TEST_FLAG(tcp_sk(sk), BPF_SOCK_OPS_STATE_CB_FLAG))
27         tcp_call_bpf_2arg(sk, BPF_SOCK_OPS_STATE_CB, oldstate, state);
28
29     switch (state) {
30     case TCP_ESTABLISHED:
31         if (oldstate != TCP_ESTABLISHED)
32             TCP_INC_STATS(sock_net(sk), TCP_MIB_CURRESTAB);
33         break;
34
35     case TCP_CLOSE:
36         if (oldstate == TCP_CLOSE_WAIT || oldstate == TCP_ESTABLISHED)
37             TCP_INC_STATS(sock_net(sk), TCP_MIB_ESTABRESETS);
38
39         sk->sk_prot->unhash(sk);
40         if (inet_csk(sk)->icsk_bind_hash &&
41             !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
42             inet_put_port(sk);
43         /* fall through */
44     default:
45         if (oldstate == TCP_ESTABLISHED)
46             TCP_DEC_STATS(sock_net(sk), TCP_MIB_CURRESTAB);
47     }
48
49     /* Change state AFTER socket is unhashed to avoid closed
50      * socket sitting in hash tables.
51      */
52     inet_sk_state_store(sk, state);
53 }

代码注释的含义为:

我们为在BPF中导出的TCP状态定义了一个新的枚举,以免强制冻结内部TCP状态。 以下检查将检测内部状态值是否与BPF值不同。 如果发生这种情况,那么我们需要在调用tcp_call_bpf_2arg之前将内部值重新映射为BPF值。

tcp_connect的功能是构造一个SYN报文并发送

 1 int tcp_connect(struct sock *sk)
 2 {
 3     struct tcp_sock *tp = tcp_sk(sk);
 4     struct sk_buff *buff;
 5     int err;
 6
 7     tcp_call_bpf(sk, BPF_SOCK_OPS_TCP_CONNECT_CB, 0, NULL);
 8
 9     if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk))
10         return -EHOSTUNREACH; /* Routing failure or similar. */
11
12     tcp_connect_init(sk);
13
14     if (unlikely(tp->repair)) {
15         tcp_finish_connect(sk, NULL);
16         return 0;
17     }
18
19     buff = sk_stream_alloc_skb(sk, 0, sk->sk_allocation, true);
20     if (unlikely(!buff))
21         return -ENOBUFS;
22
23     tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
24     tcp_mstamp_refresh(tp);
25     tp->retrans_stamp = tcp_time_stamp(tp);
26     tcp_connect_queue_skb(sk, buff);
27     tcp_ecn_send_syn(sk, buff);
28     tcp_rbtree_insert(&sk->tcp_rtx_queue, buff);
29
30     /* Send off SYN; include data in Fast Open. */
31     err = tp->fastopen_req ? tcp_send_syn_data(sk, buff) :
32           tcp_transmit_skb(sk, buff, 1, sk->sk_allocation);
33     if (err == -ECONNREFUSED)
34         return err;
35
36     /* We change tp->snd_nxt after the tcp_transmit_skb() call
37      * in order to make this packet get counted in tcpOutSegs.
38      */
39     tp->snd_nxt = tp->write_seq;
40     tp->pushed_seq = tp->write_seq;
41     buff = tcp_send_head(sk);
42     if (unlikely(buff)) {
43         tp->snd_nxt    = TCP_SKB_CB(buff)->seq;
44         tp->pushed_seq    = TCP_SKB_CB(buff)->seq;
45     }
46     TCP_INC_STATS(sock_net(sk), TCP_MIB_ACTIVEOPENS);
47
48     /* Timer for repeating the SYN until an answer. */
49     inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
50                   inet_csk(sk)->icsk_rto, TCP_RTO_MAX);
51     return 0;

我们研究这个函数\

其中调用了tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);

观察源代码

 1 static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags)
 2 {
 3     skb->ip_summed = CHECKSUM_PARTIAL;
 4
 5     TCP_SKB_CB(skb)->tcp_flags = flags;
 6     TCP_SKB_CB(skb)->sacked = 0;
 7
 8     tcp_skb_pcount_set(skb, 1);
 9
10     TCP_SKB_CB(skb)->seq = seq;
11     if (flags & (TCPHDR_SYN | TCPHDR_FIN))
12         seq++;
13     TCP_SKB_CB(skb)->end_seq = seq;
14 }

通过TCP_SKB_CB(skb)->tcp_flags = flags,把报文标志位的倒数第二位置位1,实现SYN置位

接下来分析服务器端代码

负责响应的函数是_sys_accept4:

 1 int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
 2           int __user *upeer_addrlen, int flags)
 3 {
 4     struct socket *sock, *newsock;
 5     struct file *newfile;
 6     int err, len, newfd, fput_needed;
 7     struct sockaddr_storage address;
 8
 9     if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
10         return -EINVAL;
11
12     if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
13         flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
14
15     sock = sockfd_lookup_light(fd, &err, &fput_needed);
16     if (!sock)
17         goto out;
18
19     err = -ENFILE;
20     newsock = sock_alloc();
21     if (!newsock)
22         goto out_put;
23
24     newsock->type = sock->type;
25     newsock->ops = sock->ops;
26
27     /*
28      * We don‘t need try_module_get here, as the listening socket (sock)
29      * has the protocol module (sock->ops->owner) held.
30      */
31     __module_get(newsock->ops->owner);
32
33     newfd = get_unused_fd_flags(flags);
34     if (unlikely(newfd < 0)) {
35         err = newfd;
36         sock_release(newsock);
37         goto out_put;
38     }
39     newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name);
40     if (IS_ERR(newfile)) {
41         err = PTR_ERR(newfile);
42         put_unused_fd(newfd);
43         goto out_put;
44     }
45
46     err = security_socket_accept(sock, newsock);
47     if (err)
48         goto out_fd;
49
50     err = sock->ops->accept(sock, newsock, sock->file->f_flags, false);
51     if (err < 0)
52         goto out_fd;
53
54     if (upeer_sockaddr) {
55         len = newsock->ops->getname(newsock,
56                     (struct sockaddr *)&address, 2);
57         if (len < 0) {
58             err = -ECONNABORTED;
59             goto out_fd;
60         }
61         err = move_addr_to_user(&address,
62                     len, upeer_sockaddr, upeer_addrlen);
63         if (err < 0)
64             goto out_fd;
65     }
66
67     /* File flags are not inherited via accept() unlike another OSes. */
68
69     fd_install(newfd, newfile);
70     err = newfd;
71
72 out_put:
73     fput_light(sock->file, fput_needed);
74 out:
75     return err;
76 out_fd:
77     fput(newfile);
78     put_unused_fd(newfd);
79     goto out_put;
80 }

核心是函数指针

err = sock->ops->accept(sock, newsock, sock->file->f_flags, false);

追踪这个调用,发现是调用了inet_csk_accept

源代码

 1 struct sock *inet_csk_accept(struct sock *sk, int flags, int *err, bool kern)
 2 {
 3     struct inet_connection_sock *icsk = inet_csk(sk);
 4     struct request_sock_queue *queue = &icsk->icsk_accept_queue;
 5     struct request_sock *req;
 6     struct sock *newsk;
 7     int error;
 8
 9     lock_sock(sk);
10
11     /* We need to make sure that this socket is listening,
12      * and that it has something pending.
13      */
14     error = -EINVAL;
15     if (sk->sk_state != TCP_LISTEN)
16         goto out_err;
17
18     /* Find already established connection */
19     if (reqsk_queue_empty(queue)) {
20         long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
21
22         /* If this is a non blocking socket don‘t sleep */
23         error = -EAGAIN;
24         if (!timeo)
25             goto out_err;
26
27         error = inet_csk_wait_for_connect(sk, timeo);
28         if (error)
29             goto out_err;
30     }
31     req = reqsk_queue_remove(queue, sk);
32     newsk = req->sk;
33
34     if (sk->sk_protocol == IPPROTO_TCP &&
35         tcp_rsk(req)->tfo_listener) {
36         spin_lock_bh(&queue->fastopenq.lock);
37         if (tcp_rsk(req)->tfo_listener) {
38             /* We are still waiting for the final ACK from 3WHS
39              * so can‘t free req now. Instead, we set req->sk to
40              * NULL to signify that the child socket is taken
41              * so reqsk_fastopen_remove() will free the req
42              * when 3WHS finishes (or is aborted).
43              */
44             req->sk = NULL;
45             req = NULL;
46         }
47         spin_unlock_bh(&queue->fastopenq.lock);
48     }
49 out:
50     release_sock(sk);
51     if (req)
52         reqsk_put(req);
53     return newsk;
54 out_err:
55     newsk = NULL;
56     req = NULL;
57     *err = error;
58     goto out;
59 }

这个函数的功能的功能是:从一个连接队列(已经完成三次握手)中取出控制块,若队列空,根据阻塞标志决定是直接返回还是在一定时间内阻塞并等待。

原文地址:https://www.cnblogs.com/Miliapus/p/12104428.html

时间: 2024-10-10 10:13:57

深入理解TCP协议:三次握手详解的相关文章

TCP/IP三次握手详解

原文:http://www.cnblogs.com/CBDoctor/archive/2012/10/17/2727073.html 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接. 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认: 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态: 第

TCP协议三次握手过程分析

TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标示: SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急) Sequence number(顺序号码) Acknowledge number(确认号码) 第一

TCP协议三次握手

TCP协议三次握手过程分析 TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急) Sequence number(顺序号码) Acknowledge nu

TCP协议三次握手实例

常见链路层设备:二层交换机,网桥常见物理层设备是:中继器,集线器OSI七层参考模型:应用层.表示层.会话层.传输层.网络层.数据链路层,物理层.TCP/IP的四层模型:应用层.传输层.Interent层.网络访问层 TCP协议三次握手实例:第一次握手:192.168.1.121发送位码syn=1,随机产生seq number=3626544826的数据包到192.168.1.129,由syn=1知道192.168.1.121要求建立联机:第二次握手:192.168.1.129收到请求后要确认联机

TCP协议三次握手过程分析(改)

TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标示:SYN(synchronous---同步的---建立联机) ACK(acknowledgement---确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急) seq(Sequence number---随机序号) ack(Acknowl

网络编程 TCP协议:三次握手,四次回收,反馈机制 socket套接字通信 粘包问题与解决方法

TCP协议:三次握手,四次挥手 TCP协议建立双向通道. 三次握手, 建连接: 1:客户端向服务端发送建立连接的请求 2:服务端返回收到请求的信息给客户端,并且发送往客户端建立连接的请求 3:客户端接收到服务端发来的请求,返回接成功给服务端,完成双向连接 第一客戶向服务端发送请求,请求建立连接 服务端同客户端的请求,并同时向客户端发送建立 连接的请求,最后客户端同意后建立 双向连接. C ----> S C <---- S - 反馈机制: 客户端往服务端发送请求,服务端必须返回响应, 告诉客户

TCP协议三次握手和四次挥手

http://www.cnblogs.com/rootq/articles/1377355.html TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标示:SYN(synchronous建立联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)

TCP协议三次握手与四次挥手通俗解析

TCP/IP协议三次握手与四次握手流程解析 一.TCP报文格式 TCP/IP协议的详细信息参看<TCP/IP协议详解>三卷本.下面是TCP报文格式图: 图1 TCP报文格式 上图中有几个字段需要重点介绍下: (1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记. (2)确认号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1. (3)标志位:共6个,即URG.ACK.PSH.RST.SYN.FIN等,具体含

Tcp协议三次握手跟四次挥手

一.Tcp协议(传输控制协议)1.面向连接的.可靠的进程到进程通信协议2.tcp提供双工服务,即数据统一时间可以双向传输3.tcp报文段A.tcp将若干个字节构成一个分组B.tcp报文段封装在ip数据报中4.tcp报文段的首部格式序号:发送端为每个字节进行编号,便于接受端正确重组确认号:用于确认发送端的信息SYN:同步序号位,tcp需要 连接是将该值设为1ACK:确认序号位,当该位为1时,用于确认发送方的数据FIN : 当tcp需要断开连接时,将该值设为1二.tcp连接三次握手过程,并用抓包工具

TCP三次握手详解和四次挥手

TCP的三次握手四次挥手时面试时面试官经常问道的问题 在互联网中,如何使不同网段的主机相互通信,需要用到TCP协议:TCP,提供面向连接的服务,在传送数据之前必须先建立连接,数据传送完成后要释放连接.TCP是一种可靠的的运输服务,采用三次握手建立一个连接. 首先介绍下TCP的报文格式序号 发送端为每个字节编号,方便接收端正确重组.确认号 用于确认发送端的信息.窗口大小 用于说明本地可接收数据段的数目. 标志位URG 紧急指针位 1 开启 0 关闭.不经过缓存直接提交给对方. PSH 快速接受传递