python Socket socketserver

时间:2021-06-17 16:27:49

Socket

套接字

socket的 类型 实现socket对象时传入 到socket 类中

socket.AF_INET    服务器间的通讯  IPv4
socket.AF_INET6 IPv6
socket.SOCK_STREAM 流试 tcp 传输方式 默认类型
socket.SOCK_DGRAM 包式 udp 传输方式

返回前端数据 需要先发送报头

b'HTTP/1/1 200 OK \r\n\r\n'

基于 Tcp 传输方式

服务端 server

import socket

server = socket.socket()
# 允许地址重用
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定 ip 及 端口
server.bind(("192.168.15.100", 8001))
监听 tcp 传入链接 可设置链接个数 listen(4)
server.listen()
# 等待建立链接 conn 管道 addr 客户端的地址
conn, addr = server.accept()
#接收数据
content = conn.recv(1024).decode("utf-8")
print(content)
# 发送数据
conn.send("再见".encode("utf-8")) # 循环发送数据 直到数据发送完毕
conn.sendall("再见..........".encode("utf-8"))
# 关闭
conn.close()
server.close()

客户端 client

import socket

clinet = socket.socket()
clinet.connect(("192.168.15.100", 8001))
clinet.send(st.encode("utf-8")) clinet.recv(1024).decode("utf-8") clinet.close()

基于 Udp 传输方式

服务端

import socket

server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(("127.0.0.1", 8001))
# 等待接收数据
conn, addr = server.recvfrom(1024)
st = conn.decode("utf-8")
# 向某个地址 返回数据
server.sendto(st.encode("utf-8"), addr)

客户端

import socket
clinet = socket.socket(type=socket.SOCK_DGRAM) clinet.sendto('你好啊!', ("127.0.0.1", 8001))
conn, addr = clinet.recvfrom(1024)
print(conn.decode("utf-8")) server.sendto(st.encode("utf-8"), addr)

缓冲区

作用:

​ 防止数据丢失

输入缓冲区 #recv

输出缓冲区 #send

粘包

粘包(tcp的两种粘包现象)

  1. 连续发送小的数据,并且每次发送之间的时间间隔很短(输出缓冲区:两个消息在缓冲区黏在一起了)

    原因是TCP为了传输效率,做了一个优化算法(Nagle),减少连续的小包发送(因为每个消息被包裹以后,都会有两个过程:1 组包 2拆包)

  2. 第一次服务端发送的数据比我客户端设置的一次接收消息的大小要大,那么接收不完,第二次再接收的时候,就会将第一次剩余的消息接收到

粘包的根本原因是因为:双方不知道对方发送消息的大小

  • 解决方案一:

    发送消息之前,先计算要发送消息的长度,然后先将消息长度发送过去,对方给你回一个确认收到长度的信息,然后根据接收到的消息长度来修改自己一次接收消息的大小

    这个过程多了一次交互

  • 粘包解决方案二

    使用 **struct ** 模块打包

tcp和udp的区别

​ tcp协议:面向连接,消息可靠,相对udp来讲,传输速度慢,消息是面向流的,无消息保护边界0

​ udp协议:面向无连接,消息不可靠,传输速度快,消息是面向包的,有消息保护边界.

socketserver

  • 简化网络服务端的编写

服务端 SocketServer模块与简单并发服务器

import socketserver
import struct class Myserver(socketserver.BaseRequestHandler):
# 定义一个方法 handle 方法名字不可以变
def handle(self):
try:
while 1: # 循环接受 回复 数据
# self.request 就是 conn 链接通道 client_data = self.request.recv(1024).decode("utf-8")
print(client_data)
# 返回信息
self.request.send("输入>>>".encode("utf-8"))
except ConnectionResetError as c:
print(c) if __name__ == "__main__": server_ip = ('127.0.0.1',8001)
# 地址重用
# socketserver.TCPServer.allow_reuse_address = True
# 绑定ip 端口 启动 Myserver 类 ThreadingTCPServer>>>多线程的TCP服务端
server = socketserver.ThreadingTCPServer(server_ip, Myserver)
# 永久执行下去
server.serve_forever()

FTP

#进度条打印,print版
import time
for i in range(20):
#\r 回到行首打印内容,如果同一行有内容,那么就被抹掉了
n = '>' * i
print('\r%s' %n,end='')
time.sleep(0.5) #进度条打印,sys版
import sys
import time
for i in range(10):
sys.stdout.write('>')
sys.stdout.flush()
time.sleep(0.5) #搞百分比的样子
#0.42857142857142855 改成两位数,不进行四舍五入
print(3/7) #0.42857142857142855
print(round(3/7,2)) #0.43 43%
print(int(3/7*100))