网络编程之乱七八糟的笔记

一、计算机基础

网络:

互联网协议

osi

  1. 七层: 应用层, 表, 会, 传输层, 网络层, 数据链层, 物理层
  2. 五层: 应用层(应用层, 表, 会), 传输层, 网络层, 数据链层, 物理层

五层协议详解:

  1. 物理层:

  2. 数据链路层: 以太网协议

    2.1 ethernet规定: 一组电信号构成一个数据包,叫做‘帧’
    每一数据帧分成:报头head和数据data两部分
    head data
    head包含:(固定18个字节)

    发送者/源地址,6个字节
    接收者/目标地址,6个字节
    数据类型,6个字节
    data包含:(最短46字节,最长1500字节)

    数据包的具体内容
    head长度+data长度=最短64字节,最长1518字节,超过最大限制就分片发送

    2.2 mac地址:

    2.3 以太网工作方式: 基于mac地址的广播的方式来进行数据的传递(局域网内)

  3. 网络层:

    ip协议: (ipv4, ipv6)

    arp协议(了解): 把ip地址解析成Mac地址

  4. 传输层: tcp/udp(基于端口的协议)

  5. 应用层: (http协议/ftp协议)

tcp/udp协议详解:

  1. tcp协议: 可靠协议(建立链接: 三次握手 断开链接: 四次挥手)

    image_1c1phb5ao10jb183v1l3i1psgo6037.png-281.7kB

  2. udp协议: 不可靠, 传输效率高, 网络开销低

socket:

  1. AF_UNIX
  2. AF_INET

img

服务器端: server_test.py

# -*- encoding: utf-8 -*-
"""
@author: 
@license: 
@contact: 
@software: 
@file: server_test.py
@time: 2020.8.7 11:47
@desc:
"""

import socket


# 1. 买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM ---> tcp
print(phone)

# 2. 绑定手机卡(端口: 0-65535 其中0-2014给操作系统用)
phone.bind(('127.0.0.1', 8080))

# 3.开机
phone.listen(5)

# 4. 等待链接
print('starting....')
conn, client_addr = phone.accept()
print(conn, client_addr)

# 5. 收发消息
data = conn.recv(1024)  # 单位是bytes 接收数据的最大数
print('客户端发到服务端的数据: ', data)

conn.send(data.upper())

# 6. 挂电话
conn.close()

# 7. 关机
phone.close()


客户端: client_test.py

# -*- encoding: utf-8 -*-
"""
@author: 
@license: 
@contact: 
@software: 
@file: client_test.py
@time: 2020.8.7 11:48
@desc:
"""

import socket


# 1. 买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM ---> tcp
print(phone)

# 2. 拨号
phone.connect(('127.0.0.1', 8080))

# 3. 收发消息
phone.send('xxx'.encode('utf-8'))
data = phone.recv(1024)
print(data)

# 4. 关闭
phone.close()

在my_server.bind()之前加上如下代码, 重用端口

my_sever.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

加上链接循环

my_server.py

import socket


my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(5)
# 加上链接循环
while True:
    client_conn, colient_addr = my_server.accept()
    if not colient_addr:
        my_server.close()
        break
    while True:
        try:
            res = client_conn.recv(1024)
            if res.decode('utf-8') == 'exit' or not res:
                client_conn.close()
                break
            client_conn.send(res.upper())
            print(res.decode('utf-8'))
        except ConnectionResetError:
            break

消除不能接受空字符串的bug

my_client.py

import socket


my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
while True:
    msg = input('>>> ').strip()
    if not msg:continue  # 消除不能接受空字符串的bug
    my_client.send(msg.encode('utf-8'))
    res = my_client.recv(1024)
    print(res.decode('utf-8'))
    if not res:
        break
my_client.close()

模拟ssh远程执行命令

系统命令:

win: dir: 查看某一个文件夹下的子文件名与子文件夹 ipconfig: 查看本地网卡的ip信息 tasklist: 查看运行的进程

linux: ls ifconfig ps aux

执行系统命令: os模块 —> 在终端打印

sunbprocess —> 拿到返回结果

my_server.py

"""TODO 模拟ssh远程执行命令"""
import socket
import subprocess


my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
    client_conn, colient_addr = my_server.accept()
    print(colient_addr)
    # TODO
    if not colient_addr:
        my_server.close()
        break
    while True:
        try:
            # 1. 接收命令
            cmd = client_conn.recv(1024).decode('utf-8')
            if cmd == 'exit' or not cmd:
                break

            # 2. 执行命令, 拿到结果
            obj = subprocess.Popen(cmd,
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)

            stdout = obj.stdout.read()
            stderr = obj.stderr.read()

            # 3. 把明理路结果返回给客户端
            client_conn.send(stdout + stderr)  # 存在效率问题

        except ConnectionResetError:
            break
    client_conn.close()

my_client.py

"""TODO 模拟ssh远程执行命令"""
import socket


my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
while True:
    # 1. 发命令
    cmd = input('>>> ').strip()
    if not cmd:
        continue
    my_client.send(cmd.encode('utf-8'))

    # 2. 拿到命令结果并打印
    res = my_client.recv(1024)  # 接收的数据可能超过1024个字节
    print(res.decode('gbk'))
    if not res:
        break
my_client.close()

粘包现象

关闭已运行的python程序:

​ linux: pkill -9 python

​ win: taskkill python

send和recv:

  1. send和recv都不会直接接收对方的数据, 而是操作自己的操作系统内存, 不是一个send对应一个recv

    1.1 recv: wait data(耗时非常长), copy data

    1.2 send: copy data

import struct
# 制作固定长度的报头
res = struct.pack('i', 123)
print(res, type(res), len(res))
"""b'{\x00\x00\x00' <class 'bytes'> 4"""

#
obj = struct.unpack('i', res)
print(obj, obj[0])
"""(123,) 123"""

解决粘包问题

my_server.py

"""TODO 模拟ssh远程执行命令"""
import struct
import socket
import json
import subprocess


my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
    client_conn, colient_addr = my_server.accept()
    print(colient_addr)
    # TODO
    if not colient_addr:
        my_server.close()
        break
    while True:
        try:
            # 1. 接收命令
            cmd = client_conn.recv(1024).decode('utf-8')
            if cmd == 'exit' or not cmd:
                break

            # 2. 执行命令, 拿到结果
            obj = subprocess.Popen(cmd,
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)

            stdout = obj.stdout.read()
            stderr = obj.stderr.read()

            # 3. 把命令结果返回给客户端
            # 3.1 制作固定长度的报头
            # send_count = len(stdout) + len(stderr)
            # # header = struct.pack('i', send_count)  # send_count的长度有限制
            # header = struct.pack('l', send_count)  # send_count的长度有限制
            header_dic = {
                'filename': 'a.txt',
                'md5': 'xxxxx',
                'total_size': len(stdout) + len(stderr)
            }
            header_json = json.dumps(header_dic)
            header_bytes = header_json.encode('gbk')

            # 3.2 发送报头的长度
            client_conn.send(struct.pack('i', len(header_bytes)))

            # 3.3 把报头数据发送给客户端
            client_conn.send(header_bytes)

            # 3.4 发送真实数据
            count = 0
            client_conn.send(stdout)
            client_conn.send(stderr)

        except ConnectionResetError:
            break
    client_conn.close()

my_client.py

"""TODO 模拟ssh远程执行命令"""
import socket
import struct
import json

my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
flag = True
while flag:
    # 1. 发命令
    cmd = input('>>> ').strip()
    if not cmd:
        continue
    my_client.send(cmd.encode('utf-8'))

    # 2. 拿到命令结果并打印
    # 2.1 先收报头的长度
    header_size = struct.unpack('i', my_client.recv(4))[0]

    # 2.2 接收报头数据
    header_bytes = my_client.recv(header_size)

    # 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
    header_json = header_bytes.decode('gbk')
    header_dic = json.loads(header_json)
    recv_count = header_dic['total_size']

    # 2.4 就收真实数据
    count = 0
    recv_data = b''
    while count < recv_count:
        res = my_client.recv(1024)  # 接收的数据可能超过1024个字节
        count += len(res)
        recv_data += res
    print(recv_data.decode('gbk'))
my_client.close()

my_server.py

"""TODO 文件上传下载功能"""
import struct
import socket
import json
import os

SERVER_PATH = r'E:\lufei\model_3\model_3_1\log\服务器端'


my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
    client_conn, colient_addr = my_server.accept()
    print(colient_addr)
    # TODO
    if not colient_addr:
        my_server.close()
        break
    while True:
        try:
            # 1. 接收命令
            res = client_conn.recv(1024).decode('utf-8').split()
            if res == 'exit' or not res:
                break

            # 2. 解析命令, 提取相应参数
            file_name = res[1]

            # 3. 以读的方式打开文件, 读取文件内容发送给客户端
            # 3.1 制作固定长度的报头
            header_dic = {
                'filename': file_name,
                'md5': 'xxxxx',
                'file_size': os.path.getsize('%s\%s' % (SERVER_PATH, file_name))
            }
            header_json = json.dumps(header_dic)
            header_bytes = header_json.encode('gbk')

            # 3.2 发送报头的长度
            client_conn.send(struct.pack('i', len(header_bytes)))

            # 3.3 把报头数据发送给客户端
            client_conn.send(header_bytes)

            # 3.4 发送真实数据
            with open('%s\%s' % (SERVER_PATH, file_name), 'rb') as f:
                for line in f:
                    client_conn.send(line)

        except ConnectionResetError:
            break
    client_conn.close()


my_client.py

"""TODO 文件下载上传功能"""
import socket
import struct
import json

CLIENT_PATH = r'E:\lufei\model_3\model_3_1\log\客户端'


my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
flag = True
while flag:
    # 1. 发命令
    cmd = input('>>> ').strip()
    if not cmd:
        continue
    my_client.send(cmd.encode('utf-8'))

    # 2. 以写的方式打开一个新文件, 将从服务端接收的文件内容写入客户端的新文件中
    # 2.1 先收报头的长度
    header_size = struct.unpack('i', my_client.recv(4))[0]

    # 2.2 接收报头数据
    header_bytes = my_client.recv(header_size)

    # 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
    header_json = header_bytes.decode('gbk')
    header_dic = json.loads(header_json)
    recv_count = header_dic['file_size']
    file_name = header_dic['filename']

    # 2.4 接收真实数据
    with open('%s\%s' % (CLIENT_PATH, file_name), 'wb') as f:
        count = 0
        while count < recv_count:
            line = my_client.recv(1024)  # 接收的数据可能超过1024个字节
            count += len(line)
            f.write(line)
my_client.close()

函数版本

my_server.py

"""TODO 文件上传下载功能"""
import struct
import socket
import json
import os

SERVER_PATH = r'E:\lufei\model_3\model_3_1\log\服务器端'


def get(client_conn, res):
    file_name = res[1]
    # 3. 以读的方式打开文件, 读取文件内容发送给客户端
    # 3.1 制作固定长度的报头
    header_dic = {
        'filename': file_name,
        'md5': 'xxxxx',
        'file_size': os.path.getsize('%s\%s' % (SERVER_PATH, file_name))
    }
    header_json = json.dumps(header_dic)
    header_bytes = header_json.encode('gbk')

    # 3.2 发送报头的长度
    client_conn.send(struct.pack('i', len(header_bytes)))

    # 3.3 把报头数据发送给客户端
    client_conn.send(header_bytes)

    # 3.4 发送真实数据
    with open('%s\%s' % (SERVER_PATH, file_name), 'rb') as f:
        for line in f:
            client_conn.send(line)


def run():
    my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    my_server.bind(('127.0.0.1', 8081))
    my_server.listen(3)
    while True:
        client_conn, colient_addr = my_server.accept()
        print(colient_addr)
        # TODO
        if not colient_addr:
            my_server.close()
            break
        while True:
            try:
                # 1. 接收命令
                res = client_conn.recv(1024).decode('utf-8').split()
                if res == 'exit' or not res:
                    break

                # 2. 解析命令, 提取相应参数
                if res[0] == 'get':
                    get(client_conn, res)

            except ConnectionResetError:
                break
        client_conn.close()


if __name__ == '__main__':
    run()

my_client.py

"""TODO 文件下载上传功能"""
import socket
import struct
import json

CLIENT_PATH = r'E:\lufei\model_3\model_3_1\log\客户端'


def get(my_client):
    # 2. 以写的方式打开一个新文件, 将从服务端接收的文件内容写入客户端的新文件中
    # 2.1 先收报头的长度
    header_size = struct.unpack('i', my_client.recv(4))[0]

    # 2.2 接收报头数据
    header_bytes = my_client.recv(header_size)

    # 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
    header_json = header_bytes.decode('gbk')
    header_dic = json.loads(header_json)
    recv_count = header_dic['file_size']
    file_name = header_dic['filename']

    # 2.4 接收真实数据
    with open('%s\%s' % (CLIENT_PATH, file_name), 'wb') as f:
        count = 0
        while count < recv_count:
            line = my_client.recv(1024)  # 接收的数据可能超过1024个字节
            count += len(line)
            f.write(line)


def run():
    my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    my_client.connect(('127.0.0.1', 8081))
    flag = True
    while flag:
        # 1. 发命令
        inp = input('>>> ').strip()
        if not inp:
            continue
        my_client.send(inp.encode('utf-8'))
        cmds = inp.split()
        if cmds[0] == 'get':
            get(my_client)

    my_client.close()


if __name__ == '__main__':
    run()

一、计算机基础

网络:

互联网协议

osi

  1. 七层: 应用层, 表, 会, 传输层, 网络层, 数据链层, 物理层
  2. 五层: 应用层(应用层, 表, 会), 传输层, 网络层, 数据链层, 物理层

五层协议详解:

  1. 物理层:

  2. 数据链路层: 以太网协议

    2.1 ethernet规定: 一组电信号构成一个数据包,叫做‘帧’
    每一数据帧分成:报头head和数据data两部分
    head data
    head包含:(固定18个字节)

    发送者/源地址,6个字节
    接收者/目标地址,6个字节
    数据类型,6个字节
    data包含:(最短46字节,最长1500字节)

    数据包的具体内容
    head长度+data长度=最短64字节,最长1518字节,超过最大限制就分片发送

    2.2 mac地址:

    2.3 以太网工作方式: 基于mac地址的广播的方式来进行数据的传递(局域网内)

  3. 网络层:

    ip协议: (ipv4, ipv6)

    arp协议(了解): 把ip地址解析成Mac地址

  4. 传输层: tcp/udp(基于端口的协议)

  5. 应用层: (http协议/ftp协议)

tcp/udp协议详解:

  1. tcp协议: 可靠协议(建立链接: 三次握手 断开链接: 四次挥手)

    image_1c1phb5ao10jb183v1l3i1psgo6037.png-281.7kB

  2. udp协议: 不可靠, 传输效率高, 网络开销低

socket:

  1. AF_UNIX
  2. AF_INET

img

服务器端: server_test.py

# -*- encoding: utf-8 -*-
"""
@author: 
@license: 
@contact: 
@software: 
@file: server_test.py
@time: 2020.8.7 11:47
@desc:
"""

import socket


# 1. 买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM ---> tcp
print(phone)

# 2. 绑定手机卡(端口: 0-65535 其中0-2014给操作系统用)
phone.bind(('127.0.0.1', 8080))

# 3.开机
phone.listen(5)

# 4. 等待链接
print('starting....')
conn, client_addr = phone.accept()
print(conn, client_addr)

# 5. 收发消息
data = conn.recv(1024)  # 单位是bytes 接收数据的最大数
print('客户端发到服务端的数据: ', data)

conn.send(data.upper())

# 6. 挂电话
conn.close()

# 7. 关机
phone.close()


客户端: client_test.py

# -*- encoding: utf-8 -*-
"""
@author: 
@license: 
@contact: 
@software: 
@file: client_test.py
@time: 2020.8.7 11:48
@desc:
"""

import socket


# 1. 买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM ---> tcp
print(phone)

# 2. 拨号
phone.connect(('127.0.0.1', 8080))

# 3. 收发消息
phone.send('xxx'.encode('utf-8'))
data = phone.recv(1024)
print(data)

# 4. 关闭
phone.close()

在my_server.bind()之前加上如下代码, 重用端口

my_sever.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

加上链接循环

my_server.py

import socket


my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(5)
# 加上链接循环
while True:
    client_conn, colient_addr = my_server.accept()
    if not colient_addr:
        my_server.close()
        break
    while True:
        try:
            res = client_conn.recv(1024)
            if res.decode('utf-8') == 'exit' or not res:
                client_conn.close()
                break
            client_conn.send(res.upper())
            print(res.decode('utf-8'))
        except ConnectionResetError:
            break

消除不能接受空字符串的bug

my_client.py

import socket


my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
while True:
    msg = input('>>> ').strip()
    if not msg:continue  # 消除不能接受空字符串的bug
    my_client.send(msg.encode('utf-8'))
    res = my_client.recv(1024)
    print(res.decode('utf-8'))
    if not res:
        break
my_client.close()

模拟ssh远程执行命令

系统命令:

win: dir: 查看某一个文件夹下的子文件名与子文件夹 ipconfig: 查看本地网卡的ip信息 tasklist: 查看运行的进程

linux: ls ifconfig ps aux

执行系统命令: os模块 —> 在终端打印

sunbprocess —> 拿到返回结果

my_server.py

"""TODO 模拟ssh远程执行命令"""
import socket
import subprocess


my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
    client_conn, colient_addr = my_server.accept()
    print(colient_addr)
    # TODO
    if not colient_addr:
        my_server.close()
        break
    while True:
        try:
            # 1. 接收命令
            cmd = client_conn.recv(1024).decode('utf-8')
            if cmd == 'exit' or not cmd:
                break

            # 2. 执行命令, 拿到结果
            obj = subprocess.Popen(cmd,
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)

            stdout = obj.stdout.read()
            stderr = obj.stderr.read()

            # 3. 把明理路结果返回给客户端
            client_conn.send(stdout + stderr)  # 存在效率问题

        except ConnectionResetError:
            break
    client_conn.close()

my_client.py

"""TODO 模拟ssh远程执行命令"""
import socket


my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
while True:
    # 1. 发命令
    cmd = input('>>> ').strip()
    if not cmd:
        continue
    my_client.send(cmd.encode('utf-8'))

    # 2. 拿到命令结果并打印
    res = my_client.recv(1024)  # 接收的数据可能超过1024个字节
    print(res.decode('gbk'))
    if not res:
        break
my_client.close()

粘包现象

关闭已运行的python程序:

​ linux: pkill -9 python

​ win: taskkill python

send和recv:

  1. send和recv都不会直接接收对方的数据, 而是操作自己的操作系统内存, 不是一个send对应一个recv

    1.1 recv: wait data(耗时非常长), copy data

    1.2 send: copy data

import struct
# 制作固定长度的报头
res = struct.pack('i', 123)
print(res, type(res), len(res))
"""b'{\x00\x00\x00' <class 'bytes'> 4"""

#
obj = struct.unpack('i', res)
print(obj, obj[0])
"""(123,) 123"""

解决粘包问题

my_server.py

"""TODO 模拟ssh远程执行命令"""
import struct
import socket
import json
import subprocess


my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
    client_conn, colient_addr = my_server.accept()
    print(colient_addr)
    # TODO
    if not colient_addr:
        my_server.close()
        break
    while True:
        try:
            # 1. 接收命令
            cmd = client_conn.recv(1024).decode('utf-8')
            if cmd == 'exit' or not cmd:
                break

            # 2. 执行命令, 拿到结果
            obj = subprocess.Popen(cmd,
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)

            stdout = obj.stdout.read()
            stderr = obj.stderr.read()

            # 3. 把命令结果返回给客户端
            # 3.1 制作固定长度的报头
            # send_count = len(stdout) + len(stderr)
            # # header = struct.pack('i', send_count)  # send_count的长度有限制
            # header = struct.pack('l', send_count)  # send_count的长度有限制
            header_dic = {
                'filename': 'a.txt',
                'md5': 'xxxxx',
                'total_size': len(stdout) + len(stderr)
            }
            header_json = json.dumps(header_dic)
            header_bytes = header_json.encode('gbk')

            # 3.2 发送报头的长度
            client_conn.send(struct.pack('i', len(header_bytes)))

            # 3.3 把报头数据发送给客户端
            client_conn.send(header_bytes)

            # 3.4 发送真实数据
            count = 0
            client_conn.send(stdout)
            client_conn.send(stderr)

        except ConnectionResetError:
            break
    client_conn.close()

my_client.py

"""TODO 模拟ssh远程执行命令"""
import socket
import struct
import json

my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
flag = True
while flag:
    # 1. 发命令
    cmd = input('>>> ').strip()
    if not cmd:
        continue
    my_client.send(cmd.encode('utf-8'))

    # 2. 拿到命令结果并打印
    # 2.1 先收报头的长度
    header_size = struct.unpack('i', my_client.recv(4))[0]

    # 2.2 接收报头数据
    header_bytes = my_client.recv(header_size)

    # 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
    header_json = header_bytes.decode('gbk')
    header_dic = json.loads(header_json)
    recv_count = header_dic['total_size']

    # 2.4 就收真实数据
    count = 0
    recv_data = b''
    while count < recv_count:
        res = my_client.recv(1024)  # 接收的数据可能超过1024个字节
        count += len(res)
        recv_data += res
    print(recv_data.decode('gbk'))
my_client.close()

my_server.py

"""TODO 文件上传下载功能"""
import struct
import socket
import json
import os

SERVER_PATH = r'E:\lufei\model_3\model_3_1\log\服务器端'


my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
    client_conn, colient_addr = my_server.accept()
    print(colient_addr)
    # TODO
    if not colient_addr:
        my_server.close()
        break
    while True:
        try:
            # 1. 接收命令
            res = client_conn.recv(1024).decode('utf-8').split()
            if res == 'exit' or not res:
                break

            # 2. 解析命令, 提取相应参数
            file_name = res[1]

            # 3. 以读的方式打开文件, 读取文件内容发送给客户端
            # 3.1 制作固定长度的报头
            header_dic = {
                'filename': file_name,
                'md5': 'xxxxx',
                'file_size': os.path.getsize('%s\%s' % (SERVER_PATH, file_name))
            }
            header_json = json.dumps(header_dic)
            header_bytes = header_json.encode('gbk')

            # 3.2 发送报头的长度
            client_conn.send(struct.pack('i', len(header_bytes)))

            # 3.3 把报头数据发送给客户端
            client_conn.send(header_bytes)

            # 3.4 发送真实数据
            with open('%s\%s' % (SERVER_PATH, file_name), 'rb') as f:
                for line in f:
                    client_conn.send(line)

        except ConnectionResetError:
            break
    client_conn.close()


my_client.py

"""TODO 文件下载上传功能"""
import socket
import struct
import json

CLIENT_PATH = r'E:\lufei\model_3\model_3_1\log\客户端'


my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
flag = True
while flag:
    # 1. 发命令
    cmd = input('>>> ').strip()
    if not cmd:
        continue
    my_client.send(cmd.encode('utf-8'))

    # 2. 以写的方式打开一个新文件, 将从服务端接收的文件内容写入客户端的新文件中
    # 2.1 先收报头的长度
    header_size = struct.unpack('i', my_client.recv(4))[0]

    # 2.2 接收报头数据
    header_bytes = my_client.recv(header_size)

    # 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
    header_json = header_bytes.decode('gbk')
    header_dic = json.loads(header_json)
    recv_count = header_dic['file_size']
    file_name = header_dic['filename']

    # 2.4 接收真实数据
    with open('%s\%s' % (CLIENT_PATH, file_name), 'wb') as f:
        count = 0
        while count < recv_count:
            line = my_client.recv(1024)  # 接收的数据可能超过1024个字节
            count += len(line)
            f.write(line)
my_client.close()

函数版本

my_server.py

"""TODO 文件上传下载功能"""
import struct
import socket
import json
import os

SERVER_PATH = r'E:\lufei\model_3\model_3_1\log\服务器端'


def get(client_conn, res):
    file_name = res[1]
    # 3. 以读的方式打开文件, 读取文件内容发送给客户端
    # 3.1 制作固定长度的报头
    header_dic = {
        'filename': file_name,
        'md5': 'xxxxx',
        'file_size': os.path.getsize('%s\%s' % (SERVER_PATH, file_name))
    }
    header_json = json.dumps(header_dic)
    header_bytes = header_json.encode('gbk')

    # 3.2 发送报头的长度
    client_conn.send(struct.pack('i', len(header_bytes)))

    # 3.3 把报头数据发送给客户端
    client_conn.send(header_bytes)

    # 3.4 发送真实数据
    with open('%s\%s' % (SERVER_PATH, file_name), 'rb') as f:
        for line in f:
            client_conn.send(line)


def run():
    my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    my_server.bind(('127.0.0.1', 8081))
    my_server.listen(3)
    while True:
        client_conn, colient_addr = my_server.accept()
        print(colient_addr)
        # TODO
        if not colient_addr:
            my_server.close()
            break
        while True:
            try:
                # 1. 接收命令
                res = client_conn.recv(1024).decode('utf-8').split()
                if res == 'exit' or not res:
                    break

                # 2. 解析命令, 提取相应参数
                if res[0] == 'get':
                    get(client_conn, res)

            except ConnectionResetError:
                break
        client_conn.close()


if __name__ == '__main__':
    run()

my_client.py

"""TODO 文件下载上传功能"""
import socket
import struct
import json

CLIENT_PATH = r'E:\lufei\model_3\model_3_1\log\客户端'


def get(my_client):
    # 2. 以写的方式打开一个新文件, 将从服务端接收的文件内容写入客户端的新文件中
    # 2.1 先收报头的长度
    header_size = struct.unpack('i', my_client.recv(4))[0]

    # 2.2 接收报头数据
    header_bytes = my_client.recv(header_size)

    # 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
    header_json = header_bytes.decode('gbk')
    header_dic = json.loads(header_json)
    recv_count = header_dic['file_size']
    file_name = header_dic['filename']

    # 2.4 接收真实数据
    with open('%s\%s' % (CLIENT_PATH, file_name), 'wb') as f:
        count = 0
        while count < recv_count:
            line = my_client.recv(1024)  # 接收的数据可能超过1024个字节
            count += len(line)
            f.write(line)


def run():
    my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    my_client.connect(('127.0.0.1', 8081))
    flag = True
    while flag:
        # 1. 发命令
        inp = input('>>> ').strip()
        if not inp:
            continue
        my_client.send(inp.encode('utf-8'))
        cmds = inp.split()
        if cmds[0] == 'get':
            get(my_client)

    my_client.close()


if __name__ == '__main__':
    run()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值