第1章 Python基础 Day1 基本语法
1.1 编程语言介绍与分类
1.2 Python介绍、发展趋势
1.3 Python环境安装
1.4 开发你的第一个Python程序
1.5 选择最好用的PyCharm IDE
1.6 变量
1.7 注释
1.8 基本数据类型
1.9 读取用户指令
1.10 格式化打印
1.11 运算符
1.12 流程控制之if...else
1.13 流程控制之while循环
1.14 本章练习题&作业
第2章 Python基础 Day2 数据类型和文件操作
2.1 上章补充-变量的创建过程
2.2 上章补充-身份运算和None
2.3 细讲数据类型-列表
2.4 细讲数据类型-元组
2.5 细讲数据类型-字符串
2.6 细讲数据类型-字典
2.7 细讲数据类型-集合
2.8 秒懂二进制
2.9 字符编码之文字是如何显示的
2.10 秒懂十六进制
2.11 hash是个什么东西
2.12 用Python操作文件
2.13 本章练习题&作业
第3章 Python 基础 Day3 函数编程
3.1 上章补充-Bytes类型
3.2 上章补充-字符编码的转换
3.3 上章补充-深浅copy
3.4 函数来了
3.5 函数返回值与作用域
3.6 嵌套&匿名&高阶函数
3.7 函数的递归
3.8 内置函数
3.9 名称空间
3.10 闭包是个什么东西?
3.11 函数进阶-装饰器
3.12 列表生成式
3.13 生成器
3.14 迭代器
3.15 练习题&作业
第4章 Python基础 Day4 常用模块
4.1 模块介绍与导入
4.2 第3方开源模块的安装使用
4.3 系统调用os模块
4.4 系统调用sys模块
4.5 time & datetime模块
4.6 random随机模块
4.7 序列化pickle&json模块
4.8 hashlib 加密
4.9 文件copy模块shutil
4.10 正则表达式re模块
4.11 软件开发目录设计规范
4.12 包&跨模块代码调用
4.13 练习题&作业
第5章 Python核心编程 Day5 面向对象编程
5.1 面向对象来了
5.2 面向对象语法
5.3 对象间的交互、组合
5.4 三大特性之-继承
5.5 三大特性之-封装
5.6 三大特性之-多态
5.7 作业&练习题
第6章 Python核心编程 Day6 面向对象编程进阶
6.1 类方法、静态方法
6.2 属性方法property
6.3 神奇的反射
6.4 类的双下线方法
6.5 用type动态创建一个类
6.6 isinstance\issubclass
6.7 异常处理
6.8 作业&练习题
第7章 核心编程 Day7 Socket网络编程
7.1 C/S架构介绍
7.2 TCP/IP 各层详解
7.3 Socket介绍
7.4 Socket代码实例
7.5 粘包现象与解决方案
7.6 通过socket发送文件
7.7 本章总结
第8章 核心编程 Day8 并发编程
8.1 操作系统介绍
8.2 并发编程多进程之进程理论
8.3 并发编程多进程之开启进程的两种方式
8.4 并发编程多进程之join方法
8.5 并发编程多进程之守护进程
8.6 并发编程多进程之互斥锁
8.7 并发编程多进程之队列
8.8 并发编程多进程之生产者消费者模型
8.9 并发编程多线程之线程理论
8.10 并发编程多线程之开启线程的两种方式
8.11 并发编程多线程之多线程与多进程的区别
8.12 并发编程多线程之Thread对象的其他属性或方法
8.13 并发编程多线程之守护线程
8.14 并发编程多线程之GIL全局解释器锁
8.15 并发编程多线程之死锁现象与递归锁
8.16 并发编程多线程之信号量,Event,定时器
8.17 并发编程多线程之线程queue
8.18 并发编程多线程之进程池与线程池
8.19 并发编程之协程-协程介绍
8.20 并发编程之协程-greenlet模块
8.21 并发编程之协程-gevent模块
8.22 并发编程IO模型-IO模型介绍
8.23 并发编程IO模型-阻塞IO
8.24 并发编程IO模型-非阻塞IO
8.25 并发编程IO模型-多路复用IO
8.26 并发编程IO模型-异步IO
8.27 并发编程IO模型-IO模型比较分析
8.28 并发编程IO模型-selectors模块
8.29 本章小结
第9章 Mysql数据库开发
9.1 初识数据库-数据库管理软件的由来
9.2 初识数据库-数据库概述
9.3 初识数据库-mysql安装与基本管理
9.4 初识数据库-初识sql语句
9.5 库操作-库的增删改查
9.6 表操作-存储引擎介绍
9.7 表操作-表的增删改查
9.8 表操作-数据类型
9.9 表操作-数值类型
9.10 表操作-日期类型
9.11 表操作-字符串类型
9.12 表操作-枚举类型与集合类型
9.13 表操作-完整性约束
第7章 爬虫开发-requests模块学习
7.1 requests模块初始
7.2 requests案例实战
第21章 爬虫开发-爬虫基础简介
21.1 爬虫初识&价值探讨
21.2 爬虫合法性探究
21.3 爬虫初识深入
21.4 http&https协议
第9章 爬虫开发-数据解析
9.1 数据解析概述
9.2 数据解析---正则表达式
9.3 数据解析---bs4解析
9.4 数据解析---xpath解析
第10章 爬虫开发-验证码识别
10.1 验证码识别
10.2 验证码实战
第11章 requests模块高级操作
11.1 模拟登陆
11.2 requests模块的cookie处理
11.3 requests模块的代理IP操作
第13章 高性能异步爬虫
13.1 高性能异步爬虫---线程and线程池
13.2 高性能异步爬虫---异步协程
13.3 高性能异步爬虫---多任务异步协程
13.4 高性能异步爬虫---aiohttp
第25章 scrapy框架使用
25.1 scrapy简介
25.2 scrapy的数据持久化存储
25.3 scrapy基于Spider类的全站数据爬取
25.4 请求传参
25.5 scrapy图片数据爬取
25.6 scrapy中间件
25.7 scrapy中selenium的应用
第12章 动态渲染页面爬取
12.1 图片懒加载
12.2 selenium模块基本使用
12.3 基于selenium的爬虫案例
12.4 Pyppeteer模块使用
Python入门到精通
Java放弃之路
前端开发
Linux从小白到大神
Socket代码实例
阅读量: 3501
# 本节重点: - 使学生掌握基本的socket tcp / udp 通信实例 - 让学生可通过socket写一个简单的聊天的例子 - 本节时长需控制在70-80分钟内 ## 基本Socket例子(10-15分钟) 做了这么久的铺垫,是时候该与远方的她say hi啦 Server ```python # Echo server program import socket HOST = '' # Symbolic name meaning all available interfaces PORT = 50007 # Arbitrary non-privileged port sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock_server.bind((HOST, PORT)) sock_server.listen(1) #开始监听,1代表在允许有一个连接排队,更多的新连接连进来时就会被拒绝 conn, addr = sock_server.accept() #阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象 with conn: print('Connected by', addr) while True: data = conn.recv(1024) #接收1024个字节 if not data: break #收不到数据,就break conn.sendall(data) #把收到的数据再全部返回给客户端 ``` Client ```python # Echo client program import socket HOST = 'localhost' # The remote host PORT = 50007 # The same port as used by the server client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((HOST, PORT)) client.sendall(b'Hello, world') data = client.recv(1024) print('Received',data) ``` 先启动server端,再启动client端,看结果  此时一定要停下来,让学生自己写一遍! ## 循环收发数据(15-20分钟) 第一次接触就这么交待了,只说了一句话,感觉不够过瘾,如何实现更多的交互呢?简单,只需要让客户端不断的发,服务端不断的收就可以了,写个循环搞定 server ```python # Echo server program import socket HOST = '' # Symbolic name meaning all available interfaces PORT = 50007 # Arbitrary non-privileged port sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock_server.bind((HOST, PORT)) sock_server.listen(1) #开始监听,1代表在允许有一个连接排队,更多的新连接连进来时就会被拒绝 conn, addr = sock_server.accept() #阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象 with conn: print('Connected by', addr) while True: data = conn.recv(1024) #接收1024个字节 print("server recv:",conn.getpeername(), data.decode()) if not data: break #收不到数据,就break conn.sendall(data) #把收到的数据再全部返回给客户端 ``` client ```python # Echo client program import socket HOST = 'localhost' # The remote host PORT = 50007 # The same port as used by the server client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((HOST, PORT)) while True: msg = input(">>>:").strip() if len(msg) == 0:continue client.sendall(msg.encode()) #发送用户输入的数据,必须是bytes模式 data = client.recv(1024) print('Received',data.decode()) #收到服务器的响应后,decode一下 ``` 结果  此时一定要停下来,让学生自己写一遍! ## 简单聊天软件(5分钟) 为什么上面的那个例子里,我跟杠娘说什么,她就回复什么,这哪叫聊天呀,这种事需要双方尽全力配合才行呀,那就让服务端也能说话 Server ```python import socket HOST = '' # Symbolic name meaning all available interfaces PORT = 50007 # Arbitrary non-privileged port sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock_server.bind((HOST, PORT)) sock_server.listen(1) #开始监听,1代表在允许有一个连接排队,更多的新连接连进来时就会被拒绝 conn, addr = sock_server.accept() #阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象 with conn: print('Connected by', addr) while True: data = conn.recv(1024) #接收1024个字节 print("recv from Alex:",conn.getpeername(), data.decode()) if not data: break #收不到数据,就break response = input(">>>").strip() conn.send(response.encode()) print("send to alex:",response) ``` client不需要做更改,直接 看结果  冷静的海峰玩了一会这个程序说,Alex你这个有bug,双方只能一来一往的说话,如果你想连续发2句话是不行的,就卡住了。 对,海峰你说的没错,之所以连续发第2次时会卡住 ,是因为你发了一条消息后,就去调用recv方法接收服务器的响应了,在服务器端返回消息之前,这个recv(1024)方法是阻塞的,如果想允许此时还能再发消息给服务器端,就需要再单独启动一个线程,只负责发消息。当然这就得等我们掌握了线程知识再学啦,此处不多赘述。 此处补充下listen(1)的演示,就是启动多个客户端连接同一个服务端,发现服务端只能同时处理一个请求 ## 聊天软件升级版(20-25分钟) 刚才在聊天的时候,你会发现,服务端(杠娘)在服务客户端(Alex)的时候,其它人如果也想跟杠娘连接是处于排队状态,然后等Alex完事并断开后,下一个人就跟上,但实际情况是客户端一断开,服务端也跟着断了。 为什么会断呢?因为服务端以下代码的意思是, 如果收不到数据,就跳出循环,就断开了呀 ```python conn, addr = sock_server.accept() #阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象 with conn: print('Connected by', addr) while True: data = conn.recv(1024) #接收1024个字节 print("recv from Alex:",conn.getpeername(), data.decode()) if not data: break #收不到数据,就break , 就是它干的 response = input(">>>").strip() conn.send(response.encode()) print("send to alex:",response) ``` 想实现一个客户端断开后,可以立刻接入另外一个客户端的话,怎么办呢?只需再在外层加个循环 ```python while True: #最外层loop conn, addr = sock_server.accept() #阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象 #为何把上面这句话也包含在循环里? print("来了个新客人",conn.getpeername() ) with conn: print('Connected by', addr) while True: data = conn.recv(1024) #接收1024个字节 print("recv from :",conn.getpeername(), data.decode()) if not data: break #收不到数据,就break conn.send(data.upper()) print("send to alex:",data) ``` break跳出后就回到大while那层  此时一定要停下来,让学生自己写一遍! 问题: 有的同学在重启服务端时可能会遇到  这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址(如果不懂,请深入研究1.tcp三次握手,四次挥手 2.syn洪水攻击 3.服务器高并发情况下会有大量的time_wait状态的优化方法) 解决方法1: ```python sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #一行代码搞定,写在bind之前 sock_server.bind((HOST, PORT)) ``` 解决方法2: ```python 发现系统存在大量TIME_WAIT状态的连接,通过调整linux内核参数解决, vi /etc/sysctl.conf 编辑文件,加入以下内容: net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_fin_timeout = 30 然后执行 /sbin/sysctl -p 让参数生效。 net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭; net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭; net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。 net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间 ``` 此方法全栈班的学生可直接忽略 ## UDP实例(15-20分钟) udp 不需要经过3次握手和4次挥手,不需要提前建立连接,直接发数据就行。 server端 ```python import socket ip_port=('127.0.0.1',9000) BUFSIZE=1024 udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #udp类型 udp_server_client.bind(ip_port) while True: msg,addr=udp_server_client.recvfrom(BUFSIZE) print("recv ",msg,addr) udp_server_client.sendto(msg.upper(),addr) ``` client端 ```python import socket ip_port = ('127.0.0.1',9000) BUFSIZE = 1024 udp_server_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) while True: msg=input('>>: ').strip() if not msg:continue udp_server_client.sendto(msg.encode('utf-8'),ip_port) back_msg,addr = udp_server_client.recvfrom(BUFSIZE) print(back_msg.decode('utf-8'),addr) ``` 演示  此时一定要停下来,让学生自己写一遍! ## TCP VS UDP(5分钟) tcp基于链接通信 - 基于链接,则需要listen(backlog),指定连接池的大小 - 基于链接,必须先运行的服务端,然后客户端发起链接请求 - 对于mac系统:如果一端断开了链接,那另外一端的链接也跟着完蛋recv将不会阻塞,收到的是空(解决方法是:服务端在收消息后加上if判断,空消息就break掉通信循环) - 对于windows/linux系统:如果一端断开了链接,那另外一端的链接也跟着完蛋recv将不会阻塞,收到的是空(解决方法是:服务端通信循环内加异常处理,捕捉到异常后就break掉通讯循环) udp无链接 - 无链接,因而无需listen(backlog),更加没有什么连接池之说了 - 无链接,udp的sendinto不用管是否有一个正在运行的服务端,可以己端一个劲的发消息,只不过数据丢失 - recvfrom收的数据小于sendinto发送的数据时,在mac和linux系统上数据直接丢失,在windows系统上发送的比接收的大直接报错 - 只有sendinto发送数据没有recvfrom收数据,数据丢失
Socket介绍
粘包现象与解决方案