1、什么缓冲区,为什么会有缓冲区?
缓冲区:暂时存放传输数据的,防止你的程序在发送数据的时候卡主,提高代码的运行效率
1.每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区
2.write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。
①.I/O缓冲区在每个TCP套接字中单独存在;
②.I/O缓冲区在创建套接字时自动生成;
③.即使关闭套接字也会继续传送输出缓冲区中遗留的数据;
④.关闭套接字将丢失输入缓冲区中的数据。
2、写一个tcp写一下的socket对话程序,能够优雅的断开,让另外一个客户端连接上进行收发消息。
#服务器端
import socket
s=socket.socket()
s.bind((socket.gethostname(),8001))
s.listen(666)
while 1 :
conn,addr = s.accept()
while 1 :
msg = conn.recv(1024).decode('utf-8') #先获取消息,然后判断
if msg.strip()=="bye":
break
else:
print(msg)
s1=input("你想说啥:")
conn.send(s1.encode('utf-8'))
conn.close()
s.close()
#客户端
import socket
s=socket.socket()
s.connect((socket.gethostname(),8001))
flag=0
while not flag:
info=input("请输入你要说的话(Q退出):")
if info.strip().upper()=="Q":
s.send("bye".encode('utf-8'))
flag=1
break
else:
s.send(info.encode('utf-8'))
msg=s.recv(1024)
print(msg.decode("utf-8"))
s.close()
3、自行完成今天课上写的使用subprocess进行系统调用的对话方式,客户端发送指令,服务端执行指令并且将结果返回给客户端,确保不产生粘包
#客户端
import socket
client = socket.socket()
server_ip_port = (socket.gethostname(),8001)
client.connect(server_ip_port)
while 1:
msg = input('请输入要执行的指令>>>')
client.send(msg.encode('utf-8'))
#先接收服务端要发送给我的信息的长度
from_server_msglen = int(client.recv(1024).decode('gbk'))
print('..........',from_server_msglen)
#给服务端回应一个收到了你的信息长度的确认信息
client.send('ok'.encode('utf-8'))
#拿到信息长度后,将信息长度作为参数给了recv,recv就按照这个长度大小来接受服务端后面要给我发送的数据
from_server_stdout = client.recv(from_server_msglen).decode('gbk')
print('收到的正确信息:', from_server_stdout)
# from_server_error = client.recv(1024).decode('utf-8')
# print('收到的错误信息:',from_server_error)
#服务器端
import subprocess,socket
s=socket.socket()
s.bind((socket.gethostname(),8001))
s.listen(666)
conn,addr=s.accept()
while 1 :
print("等待接收信息:")
msg=conn.recv(1024).decode("utf-8")
print(msg)
sub_obj=subprocess.Popen(
msg, #客户端指令
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
#接收到的返回消息是bytes类型的,并且windows默认的是gbk编码
s_cmd_msg=sub_obj.stdout.read()
s_cmd_err = sub_obj.stderr.read().decode('gbk')
cmd_msg_len = str(len(s_cmd_msg))
print("指令返回的正确信息的长度:",cmd_msg_len)
print('指令返回的正确信息>>>',s_cmd_msg)
print('指令返回的错误信息...',s_cmd_err)
conn.send(cmd_msg_len.encode('gbk'))
from_client_ack = conn.recv(1024).decode('utf-8')
print('from_client_ack', from_client_ack)
if from_client_ack == 'ok':
conn.send(s_cmd_msg)
else:
continue
# conn.send(server_cmd_err.encode('utf-8'))
4、什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?
1 连续发送小的数据,并且每次发送之间的时间间隔很短(输出缓冲区:两个消息在缓冲区黏在一起了)
原因是TCP为了传输效率,做了一个优化算法(Nagle),减少连续的小包发送(因为每个消息被包裹以后,都会有两个过程:1 组包 2拆包)
2 第一次服务端发送的数据比我客户端设置的一次接收消息的大小要大,那么接收不完,第二次再接收的时候,就会将第一次剩余的消息接收到
粘包的根本原因是因为:双方不知道对方发送消息的大小
解决方案一:
发送消息之前,先计算要发送消息的长度,然后先将消息长度发送过去,对方给你回一个确认收到长度的信息,然后根据接收到的消息长度来修改自己一次接收消息的大小
这个过程多了一次交互