标签:关闭 拼接 puts 发送 lse 文件 多个 多线程 coding

Socket有一个缓冲区,缓冲区是一个流,先进先出,发送和取出的可自定义大小的,如果取出的数据未取完缓冲区,则可能存在数据怠慢。造成粘包的问题
Socket发送两条连续数据时,可能最终会拼接成一条进行发送
解决方法一:
两条数据间进行延时发送,如【tiem.sleep(0.5) #延时0.5s】
解决方法二:
每次发送后等待对方确认接收信息数据,发送一条后就立即接收等待
解决方法三:
设定接收数据大小,发送端每次发送需要发送的数据的数据大小,接收端通过设置【recv(xx)】只接收确定的大小
(在client发送文件大小后面加一个recv,直到server端回复,才开始发送文件)
简单的服务器:
import socket sk = socket.socket() sk.bind((‘127.0.0.1‘,8898)) #把地址绑定到套接字 sk.listen() #监听链接 conn,addr = sk.accept() #接受客户端链接 ret = conn.recv(1024) #接收客户端信息 print(ret) #打印客户端信息 conn.send(b‘hi‘) #向客户端发送信息 conn.close() #关闭客户端套接字 sk.close() #关闭服务器套接字(可选)
简单的客户端:
import socket sk = socket.socket() # 创建客户套接字 sk.connect((‘127.0.0.1‘,8898)) # 尝试连接服务器 sk.send(b‘hello!‘) ret = sk.recv(1024) # 对话(发送/接收) print(ret) sk.close() # 关闭客户套接字
服务器进阶:实现客户循环连接及数据循环收发
import socket sk = socket.socket() sk.bind((‘127.0.0.1‘, 9999,)) sk.listen(5) while True: conn, address = sk.accept() conn.sendall(bytes(‘欢迎上传文件‘, encoding=‘utf-8‘)) file_size = str(conn.recv(1024), encoding=‘utf-8‘) conn.sendall(bytes(‘服务端:已经接收到文件大小,开始接收文件。。。‘, encoding=‘utf-8‘)) print(file_size) totle_size = int(file_size) has_recv = 0 f = open(‘1.pdf‘,‘wb‘) while True: if totle_size == has_recv: break data = conn.recv(1024) f.write(data) has_recv += len(data) f.close()
客户端进阶:
import os
import socket
obj = socket.socket()
obj.connect((‘127.0.0.1‘,9999))
ret_bytes = obj.recv(1024)
ret_str = str(ret_bytes,encoding=‘utf-8‘)
print(ret_str)
size = os.stat(‘《疯狂Python讲义》.pdf‘).st_size
obj.sendall(bytes(str(size),encoding=‘utf-8‘))
# 收到服务器确认信息,才开始发送信息
print(str(obj.recv(1024),encoding=‘utf-8‘))
with open(‘《疯狂Python讲义》.pdf‘,‘rb‘) as f:
for line in f:
obj.sendall(line)
可以监听多个文件描述符(文件句柄)(Socket对象),一旦文件句柄出现变化,即可感知
send和sendall的区别
import socket sk1 = socket.socket() sk1.bind((‘127.0.0.1‘, 8001,)) sk1.listen() sk2 = socket.socket() sk2.bind((‘127.0.0.1‘, 8002,)) sk2.listen() sk3 = socket.socket() sk3.bind((‘127.0.0.1‘, 8003,)) sk3.listen() inputs = [sk1, sk2, sk3] import select while True: # select自动监听sk1-sk3三个对象,一旦某个句柄发生变化 # 如果有人链接,就会发生变化 # 最后一个参数每次循环,最多等待一秒 # r_list表示发生变化链接,e_list表示发生错误的链接,w_list有什么值,存储什么值 r_list, w_list, e_list = select.select(inputs, [],inputs, 1) # print(r_list, w_list, e_list) # 链接上就发送一个hello for sk in r_list: conn,address = sk.accept() conn.sendall(bytes(str(‘hello world!‘),encoding=‘utf-8‘)) conn.close() for sk in e_list: inputs.remove(sk)
import socket obj = socket.socket() obj.connect((‘127.0.0.1‘,8001)) content = str(obj.recv(1024),encoding=‘utf-8‘) print(content) obj.close()
import socket
# 本质还是一个一个处理
sk1 = socket.socket()
sk1.bind((‘127.0.0.1‘, 8001,))
sk1.listen()
inputs = [sk1]
import select
while True:
# select自动监听sk1-sk3三个对象,一旦某个句柄发生变化
# 如果有人链接,就会发生变化
# 最后一个参数每次循环,最多等待一秒
# r_list表示发生变化链接,e_list表示发生错误的链接,w_list有什么值,存储什么值
r_list, w_list, e_list = select.select(inputs, [], inputs, 1)
# print(r_list, w_list, e_list)
# 链接上就发送一个hello
print("正在监听的socket对象%d,发生变化的%s" % (len(inputs), r_list))
for sk in r_list:
# 有新用户链接
if sk == sk1:
conn, address = sk.accept()
inputs.append(conn)
else:
try:
# 有老用户来链接
data = sk.recv(1024)
# 表示确实客户端确实发送数据了
data_str = str(data, encoding=‘utf-8‘)
sk.sendall(bytes(data_str, encoding=‘utf-8‘))
# 表示客户端发送为空,客户端终止的时候
except Exception as ex:
inputs.remove(sk)
for sk in e_list:
inputs.remove(sk)
import socket
obj = socket.socket()
obj.connect((‘127.0.0.1‘,8001))
while True:
inp = input(">>>")
obj.sendall(bytes(inp,encoding=‘utf-8‘))
ret = str(obj.recv(1024),encoding=‘utf-8‘)
print(ret)
obj.close()
import socket
# 本质还是一个一个处理
sk1 = socket.socket()
sk1.bind((‘127.0.0.1‘, 8001,))
sk1.listen()
inputs = [sk1, ]
outputs = []
message_dict = {}
import select
while True:
# select自动监听sk1-sk3三个对象,一旦某个句柄发生变化
# 如果有人链接,就会发生变化
# 最后一个参数每次循环,最多等待一秒
# r_list表示发生变化链接,e_list表示发生错误的链接,w_list有什么值,存储什么值
r_list, w_list, e_list = select.select(inputs, outputs, inputs, 1)
# print(r_list, w_list, e_list)
# 链接上就发送一个hello
print("正在监听的socket对象%d,发生变化的%s" % (len(inputs), r_list))
# 通过r_list和w_list实现读写分离
# r_list只用来读取信息
for sk in r_list:
# 有新用户链接
if sk == sk1:
conn, address = sk.accept()
inputs.append(conn)
# 保存用户{‘小周‘:[]}
message_dict[conn] = []
else:
try:
# 有老用户来链接
data = sk.recv(1024)
# 表示确实客户端确实发送数据了
data_str = str(data, encoding=‘utf-8‘)
# 保存收到的消息
message_dict[sk].append(data_str)
# sk.sendall(bytes(data_str, encoding=‘utf-8‘))
outputs.append(sk)
# 表示客户端发送为空,客户端终止的时候
except Exception as ex:
inputs.remove(sk)
# w_list保存谁给我发送过消息,
# w_list只用来回复信息
for conn in w_list:
# 拿到接受的消息
recv_str = message_dict[conn][0]
# 每一次取出数据后,在删除,等待下一次信息
del message_dict[conn][0]
conn.sendall(bytes(recv_str+‘好‘, encoding=‘utf-8‘))
outputs.remove(conn)
for sk in e_list:
inputs.remove(sk)
socket三阶段
socket,服务端只能处理一个请求
select + socket,伪并发
r_list:既读又写
r_list,w_list:读写分离

每次客户端链接,都创建一个线程去处理 = 同时处理所有请求,并发实现
类图关系:

源码流程
# -*- coding:utf-8 -*-
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
# print self.request,self.client_address,self.server
conn = self.request
conn.sendall(‘欢迎致电 10086,请输入1xxx,0转人工服务.‘)
Flag = True
while Flag:
data = conn.recv(1024)
if data == ‘exit‘:
Flag = False
elif data == ‘0‘:
conn.sendall(‘通过可能会被录音.balabala一大推‘)
else:
conn.sendall(‘请重新输入.‘)
if __name__ == ‘__main__‘:
# socket + select + 多线程
# 创建IP,端口,类名
# ThreadingTCPServer.init() => TCPServer.init() => BaseServer.init()
# server对象
# self.server_address (‘127.0.0.1‘,8009)
# self.RequestHandlerClass MyServer
# self.socket socket.socket()
# self.server_bind() self.socket.bind()
# self.server_activate() self.socket.listen()
server = socketserver.ThreadingTCPServer((‘127.0.0.1‘,8009),MyServer)
# server对象的serve_forever方法
# 同样,在BaseServer中找到此方法,使用方法不一样,但是可以对应
# while not self.__shutdown_request while Ture
# ready = selector.select(poll_interval)
# _ServerSelector()--->selectors.SelectSelector--->select()
# r, w, _ = self._select(self._readers, self._writers, [], timeout)
# self._handle_request_noblock()
# request, client_address = self.get_request() conn, address = sk.accept()
# self.process_request t = threading.Thread()
# self.finish_request()=> self.RequestHandlerClass(request, client_address, self) MyServer()
# self.request = request
# self.client_address = client_address
# self.server = server
# self.setup()
# try:
# self.handle() ----》 MyServer.handle() 最终目的达到
server.serve_forever()
标签:关闭 拼接 puts 发送 lse 文件 多个 多线程 coding
原文地址:https://www.cnblogs.com/shuimohei/p/13393329.html