在上一篇中我们简单的说了一下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服务器了,强化一下我们讲过的知识点。

  

 def main():
# 1.创建TCP 服务器
tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 2.绑定到指定端口
tcp_sock.bind(('', 6060))
# 3.设置为被动模式
tcp_sock.listen(128)
# 4.把服务器端设置为非阻塞模式
tcp_sock.setblocking(False) # 用来保存每个与服务器建立了连接的客户端
clients = list()
# 5.等待客户端的连接
while True:
time.sleep(1)
# 当把阻塞的东西设置为非阻塞时,一定会发成异常
try:
client_sock, addr = tcp_sock.accept()
print(client_sock) # 此时再把客户端设置为非阻塞模式,
client_sock.setblocking(False)
# 把建立好了的连接保存起来
clients.append(client_sock)
except Exception as e:
print('------------没有客户端来连接----------') for new_client in clients:
try:
# 接收数据,因为把客户端设置成了非阻塞,
# 那么所有的阻塞操作都变成了非阻塞模式
data = new_client.recv(1024).decode()
if data: # 此时客户端还在保持连接状态
print(data)
else: # 客户端已经断开连接了
new_client.close()
clients.remove(new_client)
print(data)
except Exception as e:
print('-------客户端未发送数据-------') if __name__ == '__main__':
main()

Python高级网络编程系列之第一篇的更多相关文章

  1. Python高级网络编程系列之第二篇

    在上一篇中,我们深入探讨了TCP/IP协议的11种状态,理解这些状态对我们编写服务器的时候有很大的帮助,但一般写服务器都是使用C/Java语言,因为这些语言对高并发的支持特别好.我们写的这些简单的服务 ...

  2. Python高级网络编程系列之终极篇---自己实现一个Web框架

    通过前面几个小节的学习,现在我们想要把之前学到的知识点给串联起来,实现一个很小型的Web框架.虽然很小,但是用到的知识点都是比较多的.如Socket编程,装饰器传参在实际项目中如何使用.通过这一节的学 ...

  3. Python高级网络编程系列之基础篇

    一.Socket简介 1.不同电脑上的进程如何通信? 进程间通信的首要问题是如何找到目标进程,也就是操作系统是如何唯一标识一个进程的! 在一台电脑上是只通过进程号PID,但在网络中是行不通的,因为每台 ...

  4. Python高级网络编程系列之第三篇

    在高级篇二中,我们讲解了5中常用的IO模型,理解这些常用的IO模型,对于编写服务器程序有很大的帮助,可以提高我们的并发速度!因为在网络中通信主要的部分就是IO操作.在这一篇当中我们会重点讲解在第二篇当 ...

  5. 《安卓网络编程》之第一篇 java环境下模拟客户端、服务器端

    1.Socket简介 在网络上的两个程序通过一个双向的通信连接实现数据的交换,这个双向链路的一端称为一个Socket.Socket通常用来实现客户方和服务方的连接.Socket是TCP/IP协议的一个 ...

  6. python 基础网络编程2

    python 基础网络编程2 前一篇讲了socketserver.py中BaseServer类, 下面介绍下TCPServer和UDPServer class TCPServer(BaseServer ...

  7. 猫哥网络编程系列:HTTP PEM 万能调试法

    注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新. 在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么本地环境接口可以调用成功,但放到手机上就跑 ...

  8. 猫哥网络编程系列:详解 BAT 面试题

    从产品上线前的接口开发和调试,到上线后的 bug 定位.性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期.不论你是前后端的开发岗位,还是 SQA.运维等其他技术岗位,掌握网络编程知识均是岗位的 ...

  9. 完毕port(CompletionPort)具体解释 - 手把手教你玩转网络编程系列之三

       手把手叫你玩转网络编程系列之三    完毕port(Completion Port)具体解释                                                    ...

随机推荐

  1. ABP的依赖注入

    目录 说说ABP的依赖注入 代码追踪 说说ABP的依赖注入 上篇abp运行机制分析分析了ABP在启动时,都做了那些事:这篇我们来说说ABP的最核心的一部分:依赖注入(DependencyInjecti ...

  2. Three.js开发指南---使用three.js的材质(第四章)

    材质就像物体的皮肤,决定了几何体的外表,例如是否像草地/金属,是否透明,是否显示线框等 一 材质 THREE.js的材质分为多种,Three.js提供了一个材质基类THREE.Material, 该基 ...

  3. POJ1458(KB12-L LCS)

    Common Subsequence Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 51319   Accepted: 21 ...

  4. ActiveReports 报表应用教程 (10)---交互式报表之向下钻取(详细数据按需显示解决方案)

    在葡萄城ActiveReports报表中可以动态的显示或者隐藏某区域的数据,通过该功能用户可以根据需要显示或者隐藏所关心的数据,结合数据排序.过滤等功能可以让用户更方便地分析报表数据. 本文中展示的是 ...

  5. Hive分组取Top N

    Hive在0.11.0版本开始加入了row_number.rank.dense_rank分析函数,可以查询分组排序后的top值   说明: row_number() over ([partition ...

  6. [Android] 旋转照片/图片

    今天比较闲(是任务做完了,不是偷懒),就多更新几篇,补一下之前做的东西. 原文地址请保留http://www.cnblogs.com/rossoneri/p/3995306.html 推荐阅读: An ...

  7. spring-quartz定时任务初探

    最近有关定时任务的需求还蛮多的,我这里呢用的是最简单的用法,后续了解更深层次的用法来优化目前的代码. 首先就是引入相关jar    quartz-1.6.4.jar  spring的jar就不说了 接 ...

  8. 【转】python version 2.7 required,which was not found in the registry

    源地址:http://www.cnblogs.com/thinksasa/archive/2013/08/26/3283695.html 方法:新建一个register.py 文件,把一下代码贴进去, ...

  9. 70部MAYA灯光材质渲染教程合集

    MAYA灯光材质渲染教程合集 教程格式:MP4和flv 两种格式 使用版本:教程不是一年出的教程,各个版本都有 (教程软件为英文版) 清晰度:可以看清软件上的文字 语言:部分中文字幕,其他英文(通过看 ...

  10. 联想ThinkPadE455实现FN禁用(F1-F12标准功能与特殊功能切换)

    系统:Win7 64 位     机型:联想ThinkPadE455笔记本 方法一:键盘Fn热键切换功能(亲测可用) Fn+Esc   FnLk  组合键方法启用或禁用Fn锁定功能 具体说明(这个逻辑 ...