zqfzqf

subprocess模块

1.可以帮你通过代码执行操作系统的终端命令

2.并返回终端执行命令后的结果

注意:stdout一定要在stderr前面

import subprocess

cmd=input(\'cmd>>>:\')

obj=subprocess.Popen(
    cmd,shell=True,
    stdout=subprocess.PIPE,#返回正确结果参数
    stderr=subprocess.PIPE#返回错误结果参数
)

result=obj.stdout.read()+obj.stderr.read()
print(result.decode(\'gbk\'))

粘包问题

服务端第一次发送的数据,客户端无法精确一次性接受完毕。下一次发送的数据与上一次数据粘在一起了。

1.无法预测对方需要接受的数据大小长度

2.多次连续发送数据量小,并且时间间隔短的数据一次性打包发送

TCP协议特性:

​ tcp是一个流式协议,会将多次连续发送数据量小,并且时间间隔短的数据一次性打包发送

解决粘包问题

struct模块

是一个可以将很长的数据长度,压缩成固定的长度的一个标记(数据报头)。

必须先定义报头,发送报头,再发送真实数据

即想发送文件,又想发送文件的描述信息

\'\'\'
-struct模块:
    是一个可以将很长的数据的长度,压缩成固定的长度的一个标记(数据报头)
\'\'\'
import struct
#打包压缩
# i模式,会将数据长度压缩成4个bytes
str1=\'nihaoyanihaoyanihaoya\'

# 报头

headers=struct.pack(\'i\', len(str1))

data_len=struct.unpack(\'i\',headers)
print(data_len)#(21,)
print(data_len[0])#21

解决粘包问题

#服务端
import socket
import subprocess
import struct

server=socket.socket()

server.bind((\'127.0.0.1\',9527))

server.listen(5)

while True:
    conn,addr=server.accept()
    while True:
        try:

            cmd=conn.recv(1024).decode(\'utf-8\')
            if cmd==\'q\':
                break

            if len(cmd)==0:
                continue

            print(cmd)
            # 执行cmd命令
            obj=subprocess.Popen(cmd,shell=True,
                                 stderr=subprocess.PIPE,
                                 stdout=subprocess.PIPE,)
            #接受终端返回的数据
            result=obj.stdout.read()+obj.stderr.read()
            #打包压缩,获取报头
            headers=struct.pack(\'i\',len(result))
            #发送报头
            conn.send(headers)
            #发送真实数据
            conn.send(result)
        except Exception as e:
            print(e)
            break
    conn.close()
#客户端
import socket
import struct

client=socket.socket()

client.connect((\'127.0.0.1\',9527))

while True:
    cmd=input(\'>>>:\')

    client.send(cmd.encode(\'utf-8\'))

    if cmd==\'q\':
        break
    #获取数据报头
    headers=client.recv(4)
    #解包,获取真实数据长度
    data_len=struct.unpack(\'i\',headers)
    #获取真实数据
    data=client.recv(data_len[0])

    print(data.decode(\'gbk\'))
client.close()

上传字典

#服务端
import socket
import json
import struct

server=socket.socket()
server.bind((\'127.0.0.1\',8888))
server.listen(5)

while True:
    conn,addr=server.accept()
    while True:
        try:
            headers=conn.recv(4)
            data_len=struct.unpack(\'i\',headers)[0]
            bytes_data=conn.recv(data_len)
            #先解码再反序列化
            back_dic=json.loads(bytes_data.decode(\'utf-8\'))
            print(back_dic)
        except Exception as e:
            print(e)
            break
    conn.close()
#客户端
import socket
import struct
import json
import time

cilent=socket.socket()
cilent.connect((\'127.0.0.1\',8888))
while True:
    send_dic={
        \'file_name\':\'nick真实写真集.avi\',
        \'file_size\':1000000
    }
    #json序列化,并转换成bytes类型数据
    json_data=json.dumps(send_dic)
    bytes_data=json_data.encode(\'utf-8\')

    # 先做报头
    headers=struct.pack(\'i\',len(bytes_data))
    cilent.send(headers)
    cilent.send(bytes_data)
    time.sleep(3)

上传大文件

#服务端
import socket
import json
import struct

server=socket.socket()

server.bind((\'127.0.0.1\',8888))

server.listen(3)
while True:
    conn,addr=server.accept()
    while True:
        try:
            #获取字典报头
            headers=conn.recv(4)
            #解包获取字典数据长度
            data_len=struct.unpack(\'i\',headers)[0]
            #获取字典真实数据
            bytes_dic=conn.recv(data_len)
            #樊=反序列得到字典
            back_dic=json.loads(bytes_dic.decode(\'utf-8\'))
            print(back_dic)
            #得到字典的文件名以及视频文件按的大小
            file_name=back_dic[\'file_name\']
            file_size=back_dic[\'file_size\']

            init_data=0
            #打开文件 准备写入
            with open(file_name,\'wb\') as f:
                while init_data<file_size:
                    data=conn.recv(1024)
                    f.write(data)
                    init_data+=len(data)
                    num=init_data/file_size
                    print(f\'已接受{num:.2%}\')
                print(f\'{file_name}接收完毕\')
        except Exception as e:
            print(e)
            break
    conn.close()
#客户端
import socket
import struct
import json

client=socket.socket()
client.connect((\'127.0.0.1\',8888))

#打开一个视频文件,获取视频数据大小
with open(r\'C:\Users\zqf\Desktop\新建文件夹\八重樱_桃源恋歌_1080p.mp4\',\'rb\') as f:
    movie_bytes=f.read()

# 为视频文件组织一个字典,字典内有视频文件按的名称和大小
send_dic={
    \'file_name\':\'八重樱-桃源恋歌\',
    \'file_size\':len(movie_bytes)
}

# 先打包字典 发送报头,再发送字典真实数据
json_data=json.dumps(send_dic)
bytes_data=json_data.encode(\'utf-8\')
headers=struct.pack(\'i\',len(bytes_data))

# 发送报头
client.send(headers)
#发送字典真实数据
client.send(bytes_data)

# 发送视频真实数据
init_data=0
with open(r\'C:\Users\zqf\Desktop\新建文件夹\八重樱_桃源恋歌_1080p.mp4\',\'rb\') as f:
    while init_data<len(movie_bytes):
        send_data=f.read(1024)
        client.send(send_data)
        num=init_data/len(movie_bytes)
        print(f\'数据传输{num:.2%}\')
        init_data+=len(send_data)

UDP

是一种传输协议

1.不需要建立双向管道

2.不会粘包

3.客户端给服务端发送数据,不需要等待服务端返回接受成功

4.数据容丢失,数据不安全

-TCP:好比打电话

-UDP:好比发短信

#服务端
import socket
#.SOCK_DGRAM代表了UDP
server=socket.socket(type=socket.SOCK_DGRAM)
#绑定了ip+port
server.bind((\'127.0.0.1\',8888))

msg,addr=server.recvfrom(1024)
msg1,addr1=server.recvfrom(1024)
msg2,addr2=server.recvfrom(1024)

print(msg,msg1,msg2)

#客户端
import socket

client=socket.socket(type=socket.SOCK_DGRAM)

server_ip_port=((\'127.0.0.1\',8888))

client.sendto(b\'hello\',server_ip_port)
client.sendto(b\'hello\',server_ip_port)
client.sendto(b\'hello\',server_ip_port)
client.sendto(b\'hello\',server_ip_port)
client.sendto(b\'hello\',server_ip_port)

QQ聊天室

#服务端
import socket

server=socket.socket(type=socket.SOCK_DGRAM)

server.bind((\'127.0.0.1\',8888))

while True:
    msg,addr=server.recvfrom(1024)
    print(addr)
    print(msg.decode(\'utf-8\'))

    send_msg=input("客户端向服务端发消息").encode(\'utf-8\')
    server.sendto(send_msg,addr)
#客户端
import socket

client=socket.socket(type=socket.SOCK_DGRAM)

server_ip_port=(\'127.0.0.1\',8888)
while True:
    send_msg=input(\'客户端向服务端发消息\').encode(\'utf-8\')
    client.sendto(send_msg,server_ip_port)

    msg=client.recv(1024)
    print(msg.decode(\'utf-8\'))

SocketServer

python内置模块,可以简化socket套接字服务端代码

-简化TCP/UDP服务代码

-必须要创建一个类

#服务端
import socketserver

#必须定义类
#TCP:必须继承BaseRequestHandler类
class MyTcpServer(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.client_address)
        while True:
            try:
                #request.recv==conn.recv
                data=self.request.recv(1024).decode(\'utf-8\')
                send_msg=data.upper()
                self.request.send(send_msg.encode(\'utf-8\'))

            except Exception as e:
                print(e)
                break

if __name__ == \'__main__\':
    #socketserver.TCPServer只能一个服务
    # server=socketserver.TCPServer(
    #     (\'127.0.0.1\',8888),MyTcpServer
    # )
    #
    #socketserver.ThreadingTCPServer 多个服务
    server=socketserver.ThreadingTCPServer(
        (\'127.0.0.1\', 8888), MyTcpServer
    )
    server.serve_forever()
#客户端
import socket
client=socket.socket()

client.connect(
    (\'127.0.0.1\',8888)
)
while True:
    send_msg=input(\'客户端:\')
    client.send(send_msg.encode(\'utf-8\'))
    back_msg=client.recv(1024)
    print(back_msg.decode(\'utf-8\'))


分类:

技术点:

相关文章:

  • 2021-05-08
  • 2021-09-28
  • 2021-11-26
  • 2018-12-26
  • 2018-08-17
  • 2021-03-29
  • 2021-12-24
  • 2021-09-02
猜你喜欢
  • 2021-10-21
  • 2018-07-24
  • 2018-08-14
  • 2021-09-02
  • 2021-09-09
  • 2021-09-21
  • 2021-09-26
相关资源
相似解决方案