本周内容:
day01、套接字(***)
udp
socketserver
阿里云
day02:
1、元类(***)
单例模式
2、猴子补丁
3、内置函数
4、垃圾回收机制
day03:并发编程(******)
进程起源操作系统
操作系统的发展史
==================================================================================
TCP VS UDP协议
1、可靠性
tcp协议是可靠协议:
发送一个信息后,对方必须回复一个ack确认信息(确认收到),才会将自己这端的数据从内存中删除
udp协议不可靠:
发送一条消息就会立即删除,不管对方是否接收到
,所以udp应用于对可靠性要求不高的场景
2、有无链接
tcp有链接,
udp无链接
因为没有链接请求, 所以不需要监听链接, 也即没有listen
connect是 建立连接,所以udp不需要
3、传输数据的效率
udp更高
4、粘包问题
tcp 是流式协议,把短时间内连续发送的多个信息 一起发送
udp协议称之为数据报协议,每次发送都是一个完整的数据报,一个发送唯一对应一个接收
发送一条信息,就是单独一条,所以udp协议根本就不会出现粘包问题
即使发空,也是一个完整的数据报里面包含自己的ip地址,端口,目标的ip地址端口,只不过实际数据部分是一个 空
udp协议的套接字通信:
开多个客户端与服务端进行通信,虽然看起来像是并发,
只不过由于速度很快,仍然是一个一个客户端处理的,
所以看起来像是并发的
一个客户端的阻塞,会引起其他客户端的阻塞
可以通过time.sleep() 来验证
upd可以先启动客户端, 暂时不启动服务端, 输入数据后直接发送, 只不过是发送出去的数据 就石沉大海了, 没有任何的主机接收到这条信息
而tcp必须先启动服务端,再启动客户端: 因为 tcp通信需要建立链接, 服务端如果事先不在,客户端就链接不上
socketsever模块(真正实现并发的效果)
基于 tcp协议的两个死循环
一个建立链接 一个进行通信
只需要改写 服务端就可以
两者代码之间的等效:
sever_forever() 对应 建立连接的死循环
把 conn直接赋给 severrequest对象
非并发情况下:
tcp服务端: 店里总共就一个人, 这个人先拉客(建链接), 然后再去服务(进行通信)这个客人;
服务完之后,再去拉客,然后再去服务这个客人 .......
udp也类似
并发情况下:
把 原本(只有一个主线程) 干的服务(一次服务一个人) 开成 若干个 子线程 服务(一个子线程 服务一个链接)
serve_forver 只有主线程一个人干这个 接待, 每接待一个人找另外一个服务员 服务这个链接
即专门的一个人站在店门口不停的拉客(建链接) ,为每一个客人都分配一个服务员进行服务(进行通信);
self.request
tcp中:相当于 conn
udp中:相当于 data 套接字对象
=====================================01 基于udp协议的套接字通信===================================
服务端:
from socket import *
import time
SOCK_DGRAM:数据报协议
server = socket(AF_INET, SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))
注意:udp中没有建链接的请求,所以不需要listen
所以, 既然没有建链接的请求, 也自然不需要 使用accept 建立链接
也因此,没有链接循环,直接进行通信循环即可
while True: # 通信循环
不用指定跟谁收,发给谁: 因为就是基于现成的收到的数据报中的内容实现 数据收发的
sever.recvfrom(1024) 客户端接收后,返回的内容是一个元组, 既有 ①client发过来的数据,也有 ②client端的地址
是一个元组, 进行解压操作
data, client_addr = server.recvfrom(1024)
加sleep(10): 用来验证udp通信的过程并不是并发的, 未加sleep时,看起来像是并发单纯只是因为 程序运行速度太快了
time.sleep(10)
server.sendto(data.upper(), client_addr)
客户端:
from socket import *
client = socket(AF_INET, SOCK_DGRAM)
注意: 不能出现connect, 因为connect是建链接, 而udp中没有链接
所以直接发,就ok
while True:
msg = input('输入要发送的内容: ').strip()
直接在发送的整条信息中,需要包含: ①数据内容 ②server端地址
client.sendto(msg.encode("utf-8"), ('127.0.0.1', 8080))
data, server_addr = client.recvfrom(1024)
print(data.decode('utf-8'))
===============================02 基于socketserver模块实现并发tcp===============================
服务端:
# from socket import *
#
#
# server=socket(AF_INET,SOCK_STREAM)
# server.bind(('127.0.0.1',8080))
# server.listen(5)
#
# while True:
# conn,addr=server.accept()
# print(addr)
#
# while True:
# try:
# data=conn.recv(1024)
# if len(data) == 0:break
# conn.send(data.upper())
# except Exception:
# break
#
# conn.close()
# 支持并发版本
import socketserver
# 定义一个类(类名随意), 必须继承 socketserver下面的BaseRequestHandler 这个类
class MyRequestHandler(socketserver.BaseRequestHandler):
# 在这个类中,必须要有一个handle方法: 用于处理通信 ,就把所有干通信的活儿 交给 它来干
def handle(self): # 处理通信
print(self.client_address)
while True:
try:
# 这个self.request就等同于之前的conn
# self.client_address 就是客户端的地址了
他们都封装在这个对象里面了
data = self.request.recv(1024) # self.request=>conn
if len(data) == 0: break
self.request.send(data.upper())
except Exception:
break
# 这个就等同于之前的 conn.close()
self.request.close()
# 建链接
if __name__ == '__main__':
#指明是基于TCP
s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
s.serve_forever()
客户端:
from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
msg=input(">>: ").strip()
if len(msg) == 0:
continue
client.send(msg.encode('utf-8'))
data=client.recv(1024)
print(data.decode('utf-8'))
===============================03 基于socketserver模块实现并发 udp ===============================
服务端
import socketserver
class MyRequestHandler(socketserver.BaseRequestHandler):
def handle(self): # 处理通信
data,server=self.request
server.sendto(data.upper(),self.client_address)
if __name__ == '__main__':
s = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
s.serve_forever()
客户端
from socket import *
DGRAM:即 DATA GRAM
client = socket(AF_INET, SOCK_DGRAM)
while True:
msg = input('>>: ').strip()
client.sendto(msg.encode("utf-8"), ('127.0.0.1', 8080))
data, server_addr = client.recvfrom(1024)
print(data.decode('utf-8'))
===============================04 阿里云部署===============================
服务端
# coding:utf-8
# from socket import *
#
#
# server=socket(AF_INET,SOCK_STREAM)
# server.bind(('127.0.0.1',8080))
# server.listen(5)
#
# while True:
# conn,addr=server.accept()
# print(addr)
#
# while True:
# try:
# data=conn.recv(1024)
# if len(data) == 0:break
# conn.send(data.upper())
# except Exception:
# break
#
# conn.close()
# 支持并发版本
import socketserver
class MyRequestHandler(socketserver.BaseRequestHandler):
def handle(self): # 处理通信
print(self.client_address)
while True:
try:
data = self.request.recv(1024) # self.request=>conn
if len(data) == 0: break
self.request.send(data.upper())
except Exception:
break
self.request.close()
if __name__ == '__main__':
s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
s.serve_forever()
客户端
from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('121.199.45.113',8080))
while True:
msg=input(">>: ").strip()
if len(msg) == 0:
continue
client.send(msg.encode('utf-8'))
data=client.recv(1024)
print(data.decode('utf-8'))
8-17 socketserver实现并发通信
最新推荐文章于 2020-11-29 13:54:38 发布