Day29--Python--缓冲区, 粘包

tcp: 属于长连接,与一个客户端进行连接了以后,其他的客户端要等待.要想连接另外一个客户端,需要优雅地断开当前客户端的连接

允许地址重用:
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
在bind IP地址和端口之前,写这句话,防止端口被占用无法使用.


缓冲区:
输入缓冲区 # recv
输出缓冲区 # send

什么是缓冲区,为什么会有缓冲区?
缓冲区: 暂时存放传输数据的地方.
每个socket对象被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区. 当发送消息的时候,
先将数据写入输出缓冲区中,再由TCP/UDP协议将数据从缓冲区发送到目标机器. 一旦数据写入到缓冲区,
无论是否发送到目标机器,程序都可以执行下一步操作,这样可以防止网络不畅通造成的程序阻塞.
当接收数据的时候,会从输入缓冲区中读取数据,而不是直接从网络中读取,这样cpu可以处理完当前任务后从输入缓冲区读取信息.

参考: 缓冲区与缓存
MTU:最大传输单元(Maximum Transmission Unit)
  网络层限制是1518b,每次发送数据的时候最好不要超过这个数


粘包(tcp的两种粘包现象)
1. 连续发送小的数据,并且每次发送之间的时间间隔很短. (两个消息在输出缓冲区粘连到一起)
原因是tcp为了传输效率,做了一个优化算法(Nagle),减少连续的小包发送.因为每一个消息被包裹以后都会有两个过程:
1. 组包 2. 拆包0, 会降低效率
2. 第一次服务端发送的数据比客户端设置的一次接收消息的size要大, 一次接收不完,第二次接收的时候就会把第一次剩余的消息接收到.

粘包的根本原因: 双方不知道对方发送消息的大小.
解决方案1:
发送消息之前,先计算要发送消息的长度,然后先将消息长度发送过去,对方回复确认收到,
然后根据接收到的消息长度来修改自己一次接收消息的大小.
这个过程多了一次交互

解决方案2:
第一种粘包情况可以增加发送消息的时间间隔,等缓冲区的消息发送成功后再发送后续消息

解决方案3:



# 粘包现象1 服务端

import socket

server = socket.socket()
ip_port = ('192.168.15.87', 8001)
server.bind(ip_port)

server.listen()

conn,addr = server.accept()

from_client_msg1 = conn.recv(1024).decode('utf-8')
#2000B -- 1024  976B  + 1000B
from_client_msg2 = conn.recv(1024).decode('utf-8')
#976+48 = 1024
print('msg1:',from_client_msg1)
print('msg2:',from_client_msg2)

conn.close()
server.close()
# 粘包现象1 客户端
import socket

client = socket.socket()
server_ip_port = ('192.168.15.87', 8001)
client.connect(server_ip_port)
client.send('你好!'.encode('utf-8'))
client.send('天气真好~'.encode('utf-8'))

client.close()

 

 

# 粘包现象_2_服务端
import socket
import subprocess

server = socket.socket()
ip_port = ('192.168.15.87', 8001)
server.bind(ip_port)
server.listen(3)

while 1:
    print('等待连接中...')
    tube, addr = server.accept()
    print('连接成功!')
    while 1:
        print('等待接收消息中...')
        cmd = tube.recv(1024).decode('utf-8')
        print('接收命令:%s' % cmd)
        if cmd == 'exit':
            tube.close()
            print('连接已断开!')
            break
        sub_obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        content = sub_obj.stdout.read()   # byte类型,gbk编码
        error = sub_obj.stderr.read()
        len_of_content = str(len(content)).encode('utf-8')
        len_of_error = str(len(error)).encode('utf-8')
        if len(content) == 0:
            print('即将发送消息长度为%s' % len(error))
            tube.send(len_of_error)
            tube.send(error)

        else:
            print('即将发送消息长度为%s' % len(content))
            tube.send(len_of_content)
            reply = tube.recv(1024).decode('utf-8')
            if reply == 'ack':
                print(reply)
                tube.send(content)
# 粘包现象_2_客户端
import socket

client = socket.socket()
server_ip_port = ('192.168.15.87', 8001)
client.connect(server_ip_port)

while 1:
    cmd = input('请输入命令>>>')
    client.send(cmd.encode('utf-8'))
    if cmd == 'exit':
        client.close()
        break
    len_of_msg = int(client.recv(1024).decode('utf-8'))
    print('即将接收的消息长度为:%s' % len_of_msg)
    client.send('ack'.encode('utf-8'))
    msg = client.recv(len_of_msg)
    print('实际接收到的消息长度为:%s' % len(msg))
    print(msg.decode('gbk'))

 

posted @ 2018-10-17 20:15  SuraSun  阅读(265)  评论(0编辑  收藏  举报