zoukankan      html  css  js  c++  java
  • 基于TCP的大文件发送、UDP、socketserver

    基于TCP的大文件发送

    #server服务端
    import struct
    import json
    import os
    import socket
    
    server = socket.socket()  # 默认TCP协议
    server.bind(('127.0.0.1',8080))  # 传入IP和端口
    server.listen(5)  # 限制半连接池的数量
    
    while True:
        conn,addr = server.accept()  # conn是连接,addr是地址,accept就是阻塞,等待一下,等客户端连接
        while True:
            try:
                header_dict = conn.recv(4) # 接收一个字典的报头
                dict_size = struct.unpack('i',header_dict)[0]  # 解包得到字典的长度
                dict_bytes = conn.recv(dict_size) # 接收一个字典
                dict_json = json.loads(dict_bytes.decode('utf-8'))  # 将字典解码并反序列化
                total_size = dict_json.get('file_size') #拿出字典中真实数据的大小
                recv_size = 0
                with open(dict_json.get('file_name'),'wb') as f:
                    while recv_size < total_size:
                        data = conn.recv(1024)  # 接收真实的数据
                        f.write(data)  # 将数据写入文件
                        recv_size += len(data)
                    print('上传成功')
            except ConnectionResetError as e:  # 捕获客户端断开产生的错误
                print(e)
                break
        conn.close()  # 关闭客户端套接字
    #client客户端
    import socket
    import struct
    import json
    import os
    
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    while True:
        MOVIE_DIR = r'D:Program Filesfeiqworkuntitledworksp'  # 找到文件路径
        movie_list = os.listdir(MOVIE_DIR) # 将文件夹下的文件名放到列表里
        for i,movie in enumerate(movie_list,1):  # 给列表中的文件名加上序号,从1开始
            print(i,movie)
        choice = input('请输入电影序号>>>:')
        if choice.isdigit():
            choice = int(choice) - 1
            if choice in range(0,len(movie_list)):
                path = movie_list[choice]  # 根据用户的选择,拿到文件名
                file_path = os.path.join(MOVIE_DIR,path)  # 拼接文件名的路径
                file_size = os.path.getsize(file_path)  # 获得该文件的大小
                res_d = {
                    'file_name':path,
                    'file_size':file_size,
                    'msg':'注意身体健康'
                }  # 将文件名,大小以及一些其他信息存放在字典里
                json_d = json.dumps(res_d)  # 将字典转换成json格式的数据
                json_bytes = json_d.encode('utf-8')  # 将这个数据变成二进制
                header = struct.pack('i',len(json_bytes))  # 打包一个报头,报头的内容是字典的长度
                client.send(header)  # 发送一个报头
                client.send(json_bytes)  # 发送这个字典
                with open(file_path,'rb') as f:  # 找到给文件并准备发送
                    for line in f:
                        client.send(line)  # 循环取出数据并发送
            else:
                print('not in range')
        else:
            print('must be a number')

    UDP通信

    特点:数据报协议(自带报头),没有双向通道,通信过程类似于发短信。

    1.udp协议客户端允许发空

    2.udp协议不会粘包

    3.udp协议支持并发

    ***允许发空和不会粘包的原因都是因为基于数据报协议,自带了报头

    UDP协议的基本使用:
    #服务端
    import socket
    
    server = socket.socket(type=socket.SOCK_DGRAM)  # UDP协议
    server.bind(('127.0.0.1',8080))
    #UDP不需要设置半连接池,它也没有半连接池的概念
    
    #因为没有双向通道,不需要accept,直接就到通信循环
    while True:
        data,addr = server.recvfrom(1024)
        print('数据:',data)  # 客户端发来的消息
        print('地址:',addr)  # 客户端的地址
        server.sendto(data.upper(),addr)
    
    
    #客户端
    import socket
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    # 不需要建立连接,直接进入通信循环
    server_address = ('127.0.0.1',8080)
    while True:
        client.sendto(b'hello',server_address)
        data,addr = client.recvfrom(1024)
        print('服务端发来的数据',data)
        print('服务端的地址',addr)

    简易版本的QQ

    #服务端:
    import socket
    
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1',8080))
    
    while True:
        data,addr = server.recvfrom(1024)
        print(data.decode('utf-8'))
        msg = input('>>>:')
        server.sendto(msg.encode('utf-8'),addr)
    
    
    #客户端:
    import socket
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_address = ('127.0.0.1',8080)
    
    while True:
        msg = input('>>>:')
        res = '来自客户端1的消息:%s'%msg
        client.sendto(res.encode('utf-8'),server_address)
        data,server_addr = client.recvfrom(1024)
        print(data.decode('utf-8'))

    利用socketserver完成并发

    #服务器
    import socketserver
    
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            while True:
                data, sock = self.request
                print(self.client_address)  # 客户端地址
                print(data.decode('utf-8'))
                sock.sendto(data.upper(), self.client_address)
    
    if __name__ == '__main__':
    """只要有客户端连接,会自动交给自定义类中的handl方法去处理"""    
        server = socketserver.ThreadingUDPServer(('127.0.0.1',8080), MyServer)
        server.serve_forever()  # 启动该服务对象
    
    #客户端
    import socket
    import time
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_address = ('127.0.0.1',8080)
    
    while True:
        client.sendto(b'hello',server_address)
        data,addr = client.recvfrom(1024)
        print(data.decode('utf-8'),addr)
        time.sleep(1)  # 睡眠1秒,让服务端有反馈的时间

    并发:看起来像同时运行的

    并行:真正意义上的同时运行

  • 相关阅读:
    C# 非UI线程向UI线程发送数据的两种方法
    c# 富客户端使用 MethodInvoker简化代码
    Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'xxxx'.
    弃元
    Serilog 配置基础知识
    测试软件开发准则--基于TTStand
    SuperSocketHostBuilder<TReceivePackage>
    Ext CheckBoxGroup使用
    2020年12月28日 新工作新旅程
    2021年全国计算机等级考试报名照片制作教程(压缩、裁剪、换白底)
  • 原文地址:https://www.cnblogs.com/AbrahamChen/p/11329397.html
Copyright © 2011-2022 走看看