3.4 同时打开
来源:互联网 发布:aft3登陆器源码 编辑:程序博客网 时间:2024/05/29 13:26
两个应用程序同时彼此执行connect系统调用向对方发送SYN请求,一方所使用的源|目的IP和源|目的端口恰好是对方的目的|源IP和目的|源端口,这就是“同时打开”。尽管这种情况很少见,但TCP是支持的。
这种场景下,应用进程先发送一个SYN,然后socket进入TCP_SYN_SENT状态,这时收到了对端的SYN,而非SYN|ACK。处理流程与3.3节中客户端处理SYN|ACK的相似:tcp_v4_rcv->tcp_v4_do_rcv->tcp_rcv_state_process->tcp_rcv_synsent_state_process,这时由于包中没有ACK标记,处理流程会有不同:
5373 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,5374 const struct tcphdr *th, unsigned int len)5375 {5376 struct inet_connection_sock *icsk = inet_csk(sk);5377 struct tcp_sock *tp = tcp_sk(sk);5378 struct tcp_fastopen_cookie foc = { .len = -1 };5379 int saved_clamp = tp->rx_opt.mss_clamp;...5385 if (th->ack) { //包中不带ACK标记,不会走此路径...5508 return -1;5509 }...5528 if (th->syn) {5529 /* We see SYN without ACK. It is attempt of5530 * simultaneous connect with crossed SYNs.5531 * Particularly, it can be connect to self.5532 */5533 tcp_set_state(sk, TCP_SYN_RECV);//状态切换为TCP_SYN_RECV55345535 if (tp->rx_opt.saw_tstamp) {5536 tp->rx_opt.tstamp_ok = 1;5537 tcp_store_ts_recent(tp);5538 tp->tcp_header_len =5539 sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;5540 } else {5541 tp->tcp_header_len = sizeof(struct tcphdr);5542 }55435544 tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;5545 tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;55465547 /* RFC1323: The window in SYN & SYN/ACK segments is5548 * never scaled.5549 */5550 tp->snd_wnd = ntohs(th->window);5551 tp->snd_wl1 = TCP_SKB_CB(skb)->seq;5552 tp->max_window = tp->snd_wnd;55535554 TCP_ECN_rcv_syn(tp, th);55555556 tcp_mtup_init(sk);5557 tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);5558 tcp_initialize_rcv_mss(sk);55595560 tcp_send_synack(sk);//发送SYN|ACK...5560:这个负责发送SYN|ACK的函数tcp_send_synack有些特殊:
2615 int tcp_send_synack(struct sock *sk)2616 {2617 struct sk_buff *skb;2618 2619 skb = tcp_write_queue_head(sk);2620 if (skb == NULL || !(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)) { //包一定携带SYN标记2621 pr_debug("%s: wrong queue state\n", __func__);2622 return -EFAULT;2623 }2624 if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_ACK)) { //未携带ACK标记2625 if (skb_cloned(skb)) {2626 struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);2627 if (nskb == NULL)2628 return -ENOMEM;2629 tcp_unlink_write_queue(skb, sk);2630 skb_header_release(nskb);2631 __tcp_add_write_queue_head(sk, nskb);2632 sk_wmem_free_skb(sk, skb);2633 sk->sk_wmem_queued += nskb->truesize;2634 sk_mem_charge(sk, nskb->truesize);2635 skb = nskb;2636 }2637 2638 TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ACK; //加上ACK标记2639 TCP_ECN_send_synack(tcp_sk(sk), skb);2640 }2641 TCP_SKB_CB(skb)->when = tcp_time_stamp;2642 return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); //发送出去2643 }在同时打开的情况下,发送队列中已经有一个SYN包等待确认。tcp_send_synack的基本功能是:将发送队列中的SYN包加上ACK标记位再发送。这样TCP收到SYN后发送的SYN|ACK的序列号与最开始发送的SYN包一致,从而使得收到对端的SYN|ACK包时,如果仅仅把这个包当做ACK使用,则其确认号正好可以确认掉之前发送的SYN|ACK,这样连接就可以在收到对端的SYN|ACK后得以正常建立。
2625-2635:如果队列中的SYN包是clone的副本,则这个skb与原本共享数据;为了不影响原本,必须copy一个新的skb——nskb(使用skb_copy产生的nskb与其源skb的数据完全一致,但承载数据的内存区完全独立的),加入ACK标记后再发送,而原来的skb必须释放掉。
SYN|ACK接收时会被当做ACK处理,流程与C/S模式下的server一致,不同的是查找连接时会在established表中找到socket,无需再建立新的socket。
在同时打开模式下,两端的TCP的数据交互流程都是:
1、发送SYN,TCP状态机跳转到TCP_SYN_SENT
2、收到SYN,TCP状态机跳转到TCP_SYN_RECV,发送SYN|ACK
3、收到ACK(被忽略SYN标记的SYN|ACK),TCP状态机跳转到TCP_ESTABLISHED,进入可以进行数据交互的状态。
接下来的数据交互并不受连接建立方式的影响,即无论是用C/S模式下的三次握手还是同时打开的方法建立的连接,连接建立完毕后的行为都是完全一样的。
0 0
- 3.4 同时打开
- 同时打开两个页面
- 同时打开两个Tomcat
- 双camera同时打开
- 双camera同时打开
- tcp/ip 同时打开 同时关闭
- TCP同时打开和同时关闭
- vc同时打开两个工程
- vc同时打开两个工程
- 同时打开多个进程
- eclipse 同时打开两个文件
- 同时打开多个Eclipse
- 同时打开多个软件
- 同时打开多个模拟器
- TCP连接的同时打开和同时关闭
- Vc++6.0如何同时打开两个文件
- vc能否同时打开两个工程
- 关闭窗体的同时打开另一个窗体
- iOS/Xcode 自动生成注释
- centos 用户和组,权限,添加删除详解
- 程序员在互联网公司和行业软件公司工作,有什么区别?
- Linux下select, poll和epoll IO模型的详解
- 数据库事务与其隔离级别
- 3.4 同时打开
- Opengl es+win7
- 【JAVA】【NIO】6、Java NIO Channel to Channel Transfers
- IOS开发者证书申请及应用上线发布详解
- Qt中打开excel文件
- MySQL保存为.sql文件和从.SQL文件复制MySQL数据库
- UVa 11349 - Symmetric Matrix
- 蓝天碧水中国梦-新能源汽车(1)-汽车非石化能源动力对比
- 重定向