博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python高级网络编程系列之第一篇
阅读量:6814 次
发布时间:2019-06-26

本文共 2741 字,大约阅读时间需要 9 分钟。

  在中我们简单的说了一下Python中网络编程的基础知识(相关API就不解释了),其中还有什么细节的知识点没有进行说明,如什么是TCP/IP协议有几种状态,什么是TCP三次握手,什么是TCP四次握手以及如何设计一个单线程多任务版的TCP服务器,这些问题都是本文需要解决的问题。

 

一、TCP/IP的11种状态

  netstat -na  | grep port_num:可以查看TCP/IP状态

  一个完整的Socket通信过程,会经过11种TCP/IP状态,状态图如下:

  

思考三个问题:

1.为什么TCP/IP通信前需要三次握手?

  因为TCP是全双工协议,得先建立连接才能实现任意一方接收和发送数据的功能,因此需要进行安全认证!这就好比在战争年代,使用电台发送情报一样。

  当A想要与B通信时,A需要发送一个SYN包a给到B,当B收到这个包时,会发送一个ACK a+1的包回给B,同时还要发送一个SYN b给A,确认你是不是要与我通信,然后当A发送ACK b+1给到B时,B收到这个包,那么证明A是对的人,这样A与B之间就能成功建立连接,他们之间就可以相互通信了。

 

2.为什么TCP/IP断开时需要四次挥手?

  1). 为什么要显式调用两次close()函数?

  当任意一方(假设为A)先调用close()函数时,此时A就不能发送和接收数据了。但是这并不影响另一方(假设为B),也就是说B还可以往TCP/IP缓冲区中写入数据,只不过当内核往A发送数据时会发生错误。当B也调用close()函数时,说明B也要关闭套接字了,就不再发送和接收数据了,他们的通信也就结束了。

  2).FIN_TIME_2状态:

  该状态也称为半连接状态。当A调用close()函数时,此时会在数据流的末尾加上0,当B接收到数据时,read()函数返回0,说明A已经关闭了,那么TCP/IP会偷偷的向A发送一个确认状态,但是B还没有关闭,此时A就处于半连接状态了。

  为什么会出现半连接状态呢?

    因为当B端的read()返回0时,TCP/IP协议知道A已经关闭了,但B还没有调用close()函数,而且TCP/IP协议又是双通道协议,只要B没有关闭,那么B还是可以进行读和写操作的。因此A就不能继续往前推进到TIME_WAIT状态。

  3). TIME_WAIT状态:

  主动关闭的的那一端A最终会推进到TIME_WAIT状态,只有当对方B也关闭了。只不过要等一会(2MSL)再关闭,因为存在网络延迟的原因导致最后一个确认包没能及时发送出去。当处于TIME_WAIT状态时,如果ACY y+1发送失败时,可以重新发送,保证对方真正处于关闭状态。这也是为什么会出现端口可重用选项的原因。

 

3.在状态图中,我们只看到了10种状态,那还有一种是什么?

  还有一种是CLOSING状态,这种状态比较特殊,只有当双方同时关闭的时候才会出现,状态图变化如下:

    

 

二、一个简单版的非阻塞服务器

  在经过了上面对TCP/IP协议的详细分析之后,我们可以写一个稍微复杂一些的TCP服务器了,强化一下我们讲过的知识点。

  

1 def main(): 2     # 1.创建TCP 服务器 3     tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 4     tcp_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 5     # 2.绑定到指定端口 6     tcp_sock.bind(('', 6060)) 7     # 3.设置为被动模式 8     tcp_sock.listen(128) 9     # 4.把服务器端设置为非阻塞模式10     tcp_sock.setblocking(False)11 12     # 用来保存每个与服务器建立了连接的客户端13     clients = list()14     # 5.等待客户端的连接15     while True:16         time.sleep(1)17         # 当把阻塞的东西设置为非阻塞时,一定会发成异常18         try:19             client_sock, addr = tcp_sock.accept()20             print(client_sock)21 22             # 此时再把客户端设置为非阻塞模式,23             client_sock.setblocking(False)24             # 把建立好了的连接保存起来25             clients.append(client_sock)26         except Exception as e:27             print('------------没有客户端来连接----------')28 29         for new_client in clients:30             try:31                 # 接收数据,因为把客户端设置成了非阻塞,32                 # 那么所有的阻塞操作都变成了非阻塞模式33                 data = new_client.recv(1024).decode()34                 if data: # 此时客户端还在保持连接状态35                     print(data)36                 else: # 客户端已经断开连接了37                     new_client.close()38                     clients.remove(new_client)39                 print(data)40             except Exception as e:41                 print('-------客户端未发送数据-------')42 43 44 if __name__ == '__main__':45     main()

 

转载于:https://www.cnblogs.com/fangtaoa/p/9042515.html

你可能感兴趣的文章
第 8 章 容器网络 - 068 - 分析 Calico 的网络结构
查看>>
全面掌握ping命令(三) ping命令防火墙设置
查看>>
GhostDoc使用与原始注释
查看>>
简单的邮件协议服务介绍
查看>>
宏和函数的区别
查看>>
Dubbo架构设计详解
查看>>
常用十大python机器学习库
查看>>
手机游戏渠道SDK接入工具项目分享(一)缘起
查看>>
如何做好一个程序员
查看>>
Python学习笔记__12.3章 base64
查看>>
Python学习笔记__8.4章 文档测试
查看>>
从零开始的linux 第十二章
查看>>
openstack-11:安装dashiboard界面
查看>>
隐藏权限lsattr_chattr
查看>>
VRRP冗余 RIP/OSPF STP配置
查看>>
乐搏讲自动化测试-Python发展背景(1)
查看>>
对于 wepy 不是内部或外部命令 -- 的解决办法
查看>>
嵌入式文件系统简介(一) —— Linux MTD设备文件系统
查看>>
洞悉物联网发展1000问之全屋智能是智能家居的新出路吗?
查看>>
Nginx服务与LNMP架构部署
查看>>