一、上节回顾:

1、网络=物理连接介质+互联网协议

2、OSI七层:应、表、会、传(tcp/udp),网(IP),数(ethernet),物

3、Tep三次握手建立连接,四次挥手断开连接

   connet()————>accept()

4、ip+port:标识全世界范围内独一无二的一个应用程序

  server.bind((ip,port))

5、C/S

  Client:ip+port会随意变

  Server:

    一定要绑定ip+port

    应该支持并发连接

    服务端一旦开启一直运行到世界末日

二、今日内容:

 坑:reve(1024)

粘包问题:自定义应用层协议

TCP:流式协议

1、 操作命令:

  (1)dir   查看当前文件夹下有哪些子文件夹

(2)tasklist   查看运行的哪些程序:

(3)管道符: tasklist : findstr  pychar

(4) ipconfig   查看IP配置  

2、subprosess  模块

import subprocess
obj=subprocess.Popen("dir",shell=True,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE,
                     )
print(obj.stdout.read().decode("gbk"))
print(obj.stderr.read().decode("gbk"))

解析:管道的内容只能取一次(服务端)

3、粘包现象: TCP的nagle 算法

  只有TCP 才会出现粘包现象(TCP协议是流式协议)

   粘包:把数据量较小并且时间间隔比较短的包合成一个包发送

  “linux:网卡最大 参数单元:1500个字节   (千兆网卡)
  以太网 是物理层上面的 也是*网卡“
  万兆网卡 是光纤模块 (最大参数单元)
  如果超出字节分片发送(以太网协议 的标准)

 4、struct模块

import struct
# 帮我们把数字转成固定长度的bytes类型
res=struct.pack("i",12323)
print(res,len(res))
#将bytes 类型转为数字
res1=struct.unpack("i",res)
print(res1[0])

5、json模块:

import json
header_dic={
    'md5':'asdfasdfasdfasdfasdfasdf',
    'total_size':11111111111111111111,
    'filename':'a.txt'
 }

header_json=json.dumps(header_dic)
header_bytes=header_json.encode('utf-8')
print(len(header_bytes))
header_size=struct.pack('i',len(header_bytes))
print(header_size)

6、流程:

完整版:

 

 7、解决粘包问题:

import subprocess
import struct
import json
from socket import *
server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8090))
# print(server)
server.listen(5)
while True:
    conn,addr=server.accept()
    # print(conn)
    print(addr)
    while True:
        try:
            cmd=conn.recv(8096)
            if not cmd:break #针对linux

            #执行命令
            cmd=cmd.decode('utf-8')
            #调用模块,执行命令,并且收集命令的执行结果,而不是打印
            obj = subprocess.Popen(cmd, shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   )
            stdout=obj.stdout.read()
            stderr=obj.stderr.read()


            # 1:先制作报头,报头里放:数据大小, md5, 文件
            header_dic = {
                'total_size':len(stdout)+len(stderr),
                'md5': 'xxxxxxxxxxxxxxxxxxx',
                'filename': 'xxxxx',
                'xxxxx':'123123'
            }
            header_json = json.dumps(header_dic)
            header_bytes = header_json.encode('utf-8')
            header_size = struct.pack('i', len(header_bytes))

            # 2: 先发报头的长度
            conn.send(header_size)

            # 3:先发报头
            conn.send(header_bytes)

            # 4:再发送真实数据
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break
    conn.close()

server.close()
服务端
import struct
import json
from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8089))

while True:
    cmd=input('>>: ').strip()
    if not cmd:continue
    client.send(cmd.encode('utf-8'))

    # 1:先收报头长度
    obj = client.recv(4)
    header_size = struct.unpack('i', obj)[0]

    # 2:先收报头,解出报头内容
    header_bytes = client.recv(header_size)
    header_json = header_bytes.decode('utf-8')
    header_dic = json.loads(header_json)

    print(header_dic)
    total_size = header_dic['total_size']

    # 3:循环收完整数据
    recv_size=0
    res=b''
    while recv_size < total_size:
        recv_data=client.recv(1024)
        res+=recv_data
        recv_size+=len(recv_data)
    print(res.decode('gbk'))

client.close()
客户端