zoukankan      html  css  js  c++  java
  • TCP大文件发送案例以及UDP介绍

    基于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__':
    """只要有客户端连接,会自动交给自定义类中的handle方法去处理"""    
        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秒,让服务端有反馈的时间

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

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

  • 相关阅读:
    vue:自定义指令
    vue去掉严格开发,即去掉vue-cli安装时的eslint
    vue路由6:导航钩子
    vue路由5:命名视图
    vue路由3:子路由
    vue组件通信之任意级组件之间的通信
    vue中组件通信之子父通信
    令狐冲也是个情场高手啊
    Java —— 时区(夏令时)问题
    PL/SQL 如何导出INSERT语句
  • 原文地址:https://www.cnblogs.com/wangnanfei/p/11323024.html
Copyright © 2011-2022 走看看