TCP小结
socket套接字
TCP
1
.最简易的版本的客户端与服务端之间通信
2
.通信循环
recv() 阻塞
3
.连接循环
accept() 阻塞
4
.TCP粘包问题
5
.struct模块 对数据进行打包处理 固定长度
pack
unpack
小结
解决粘包问题的流程
服务端
1
.生成一个字典
2
.制作该字典的报头
json序列化
编码 统计长度
3
.发送字典的报头
4
.发送字典
5.最后发真实数据
服务端
客户端
1
.先接受固定长度的4个字节字典报头
2
.解析获取字典数据的长度
unpack(...)[0]
3
.接受字典数据
解码 反序列化
4.接受真实数据
客户端
为什么要多加一个字典
1
.打包的数据大小有限
2.可以携带更多的信息
上传电影练习
import socket
import json
import struct
server =
socket.socket()
server.bind(('127.0.0.1',8080
))
server.listen(5
)
while True:
conn,addr =
server.accept()
while True:
try:
header_len = conn.recv(4
)
# 解析字典报头
header_len = struct.unpack(
'i',header_len)[0]
# 再接收字典数据
header_dic =
conn.recv(header_len)
# 反序列化 得到真实数据
real_dic = json.loads(header_dic.decode(
'utf-8'))
# 获取数据长度
total_size = real_dic.get(
'file_size')
# 循环接收并写入文件
recv_size =
0
with open(real_dic.get('file_name'),
'wb') as f:
while recv_size <
total_size:
data = conn.recv(1024
)
f.write(data)
recv_size +=
len(data)
print(
'上传成功')
except ConnectionResetError as e:
print(e)
break
conn.close()
服务端
import socket
import json
import os
import struct
client =
socket.socket()
client.connect(('127.0.0.1',8080
))
while True:
# 获取电影列表 循环展示
MOVIE_DIR = r
'D:\python脱产10期视频\day25\视频'
movie_list =
os.listdir(MOVIE_DIR)
# print(movie_list)
for i,movie
in enumerate(movie_list,1
):
print(i,movie)
# 用户选择
choice = input(
'please choice movie to upload>>>:')
# 判断是否是数字
if choice.isdigit():
# 将字符串数字转为int
choice = int(choice) - 1
# 判断用户选择在不在列表范围内
if choice
in range(0,len(movie_list)):
# 获取到用户想上传的文件路径
path =
movie_list[choice]
# 拼接文件的绝对路径
file_path =
os.path.join(MOVIE_DIR,path)
# 获取文件大小
file_size =
os.path.getsize(file_path)
# 定义一个字典
res_d =
{
'file_name':
'性感荷官在线发牌.mp4',
'file_size':file_size,
'msg':
'注意身体,多喝营养快线'
}
# 序列化字典
json_d =
json.dumps(res_d)
json_bytes = json_d.encode(
'utf-8')
# 1.先制作字典格式的报头
header = struct.pack(
'i',len(json_bytes))
# 2.发送字典的报头
client.send(header)
# 3.再发字典
client.send(json_bytes)
# 4.再发文件数据(打开文件循环发送)
with open(file_path,
'rb') as f:
for line
in f:
client.send(line)
else:
print(
'not in range')
else:
print(
'must be a number')
客户端
异常
程序在运行过程中出现了不可预知的错误
并且该错误没有对应的处理机制,那么就会以异常的形式表现出来
造成的影响就是整个程序无法再正常运
异常的结构
1
.异常的类型:NAMEERROR
2.异常的信息:name
'fdsdfsdf' is not defined
3
.异常的位置:Traceback (most recent call last):
File "D:/python/day29/01 异常处理.py", line 1,
in <module>
异常的种类
分为两大类
1
.语法错误
是你程序立刻就能解决的,这种错误是不能被容忍的
语法上的错误 发现之后应该立刻解决
2
.逻辑错误
这种错是可以被容忍的 因为一眼看不出来
针对逻辑上的错误 可以采用异常处理机制进行捕获
常见的错误类型
NAMERROR 名字错误
SyntaxError 语法错误
KeyError 键不存在
ValueError 值错误
IndexError 索引错误
TypeError 类型错误
如何避免
异常处理
在你认为可能会出现bug的代码块上方try一下:注意try内部的代码块越少越好
try: 可能出错的代码except 出错的类型 as e: # 将报错信息赋值给变量e 出错之后的处理机制
UDP
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection 参考模型中一种无连接的传输层协议,提供简单不可靠信息传送服务
是一种无连接的传输层协议,它主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成。且不对传送数据包进行可靠性保证,适合于一次传输少量数据
UDP使用
import socket
client = socket.socket(type=
socket.SOCK_DGRAM)
# 不需要建立双向连接 直接收发数据
server_addres = (
'127.0.0.1',8080
)
# 发送数据需要对方的大致
while True:
client.sendto(b'strawberry',server_addres)
data , addr = client.recvfrom(1024
)
print(
'服务端发的数据',data)
print(
'服务端发的地址',addr)
服务端
import socket
# UDP中要指定type=socket.SOCK_DGRAM,默认代表的是TCP
server = socket.socket(type=
socket.SOCK_DGRAM)
server.bind(('127.0.0.1',8080
))
# UDP不需要设置半连接池,它也没有半连接池的概念
# 因为没有双向通道, 不需要accept来建立双向连接,也就不需要循环连接,直接通信循环
while True:
data, addr = server.recvfrom(1024
)
print(
'数据', data)
# 客户端的数据
print(
'地址',addr)
#客户端的地址
server.sendto(data.upper(),addr)
#发送数据需要客户端的地址
客户端
TCP与UDP之间的区别
tcp 和udp
tcp:可靠,传输安全,粘包
通过连接传输:在发送数据时,会等到对方确定接收完成时,将数据删除,如果没有,就会保存到内存,等待确认
udp:不可靠,不须建立连接,不粘包,
发送数据,一旦发送,就会删除缓存数据,如果没收到,那就没收到
与TCP的区别 *****
不可靠传输
不需要建立连接
不会粘包
单次数据包不能太大
服务器端
服务器不需要监听 listen
不需要接收请求 accept
收数据 recvfrom(缓冲区大小)
发数据 sendto(数据,地址)
客户端:
不需要建立连接
收数据 recvfrom(缓冲区大小)
发数据 sendto(数据,地址)
流程
import socket
server = socket.socket(type=
socket.SOCK_DGRAM)
server.bind(('127.0.0.1',8080
))
# while True:
data, addr = server.recvfrom(1024
)
print(data)
data, addr1 = server.recvfrom(1024
)
print(data)
data, addr2 = server.recvfrom(1024
)
print(data)
服务端
import socket
client = socket.socket(type=
socket.SOCK_DGRAM)
server_address = (
'127.0.0.1',8080
)
# while True:
# msg = input('>>>:')
client.sendto(b
'hello',server_address)
client.sendto(b'hello',server_address)
client.sendto(b'hello',server_address)
# data, server_addr = client.recvfrom(1024)
# print(data
客户端
UDP实现简易版本的QQ
实现多个用户同时发信息(实现并发)
并发:看起来像同时运行的并行:真正意义上的同时运行
import socket
server = socket.socket(type=
socket.SOCK_DGRAM)
server.bind(('127.0.0.1',8080
))
while True:
data, addr = server.recvfrom(1024
)
print(data.decode(
'utf-8'))
msg = input(
'>>>:')
server.sendto(msg.encode('utf-8'),addr)
服务端
import socket
client = socket.socket(type=
socket.SOCK_DGRAM)
server_address = (
'127.0.0.1',8080
)
while True:
msg = input(
'>>>:')
msg =
'来自客户端1的消息:%s'%
msg
client.sendto(msg.encode('utf-8'),server_address)
data, server_addr = client.recvfrom(1024
)
print(data.decode(
'utf-8'))
客户端1
import socket
client = socket.socket(type=
socket.SOCK_DGRAM)
server_address = (
'127.0.0.1',8080
)
while True:
msg = input(
'>>>:')
msg =
'来自客户端2的消息:%s'%
msg
client.sendto(msg.encode('utf-8'),server_address)
data, server_addr = client.recvfrom(1024
)
print(data.decode(
'utf-8'))
客户端2
import socket
client = socket.socket(type=
socket.SOCK_DGRAM)
server_address = (
'127.0.0.1',8080
)
while True:
msg = input(
'>>>:')
msg =
'来自客户端3的消息:%s'%
msg
client.sendto(msg.encode('utf-8'),server_address)
data, server_addr = client.recvfrom(1024
)
print(data.decode(
'utf-8'))
客户端3
socketserver模块
socketserver模块是基于socket而来的模块,它是在socket的基础上进行了一层封装,并且实现并发等功能。
ThreadingTCPServer的使用方法
1
、创建一个继承socketserver.BaseRequestHandler的类
2
、类中必须重写一个名为handler的方法
3
、实例化一个服务器类,传入服务器的地址和请求处理程序类
4、调用serve_forever()事件循环监听
代码
#!/usr/bin/env python3
import socketserver
class Handler(socketserver.BaseRequestHandler):
# 必须继承BaseRequestHandler
def handle(self):
# 必须有handle方法
print(
'New connection:',self.client_address)
while True:
data = self.request.recv(1024
)
if not data:
break
print(
'Client data:',data.decode())
self.request.send(data)
if __name__ ==
'__main__':
server = socketserver.ThreadingTCPServer((
'127.0.0.1',8009),Handler)
# 实例化对象,实现多线程的socket
server.serve_forever()
# 事件监听,并调用handler方法
View Code
让tcp也能够实现udp能够看起来多个客户在运行
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
# print('来啦 老弟')
while True:
data = self.request.recv(1024
)
print(self.client_address)
# 客户端地址
print(data.decode(
'utf-8'))
self.request.send(data.upper())
if __name__ ==
'__main__':
"""只要有客户端连接 会自动交给自定义类中的handle方法去处理"""
server = socketserver.ThreadingTCPServer((
'127.0.0.1',8080),MyServer)
# 创建一个基于TCP的对象
server.serve_forever()
# 启动该服务对象
服务端
server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer) # 创建一个基于TCP的对象
ThreadingTCPServer多线程tcpserver 会帮你实时监听代码中的地址,一旦有用户来进行请求,它会将这个用户交给MyServer类中的handl方法来处理,会自动触发方法.
import socket
client =
socket.socket()
client.connect(('127.0.0.1',8080
))
while True:
client.send(b'hello')
data = client.recv(1024
)
print(data.decode(
'utf-8'))
客户端
开udp 支持并发
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
# print('来啦 老弟')
while True:
data,sock =
self.request
print(self.client_address)
# 客户端地址
print(data.decode(
'utf-8'))
sock.sendto(data.upper(),self.client_address)
if __name__ ==
'__main__':
"""只要有客户端连接 会自动交给自定义类中的handle方法去处理"""
server = socketserver.ThreadingUDPServer((
'127.0.0.1',8080),MyServer)
# 创建一个基于TCP的对象
server.serve_forever()
# 启动该服务对象
服务端
import socket
import time
client = socket.socket(type=
socket.SOCK_DGRAM)
server_address = (
'127.0.0.1',8080
)
while True:
client.sendto(b'hello',server_address)
data,addr = client.recvfrom(1024
)
print(data.decode(
'utf-8'),addr)
time.sleep(1)
客户端
转载于:https://www.cnblogs.com/komorebi/p/11324065.html