zoukankan      html  css  js  c++  java
  • udp协议 及相关 利用tcp上传文件 socketserver服务

    一、利用tcp协议上传大文件
    
    
    服务端:
    import socket
    import json
    import struct
    import os
    
    server = socket.socket()
    server.bind(('127.0.0.1', 8082))
    server.listen(5)
    
    while True:
        conn,addr = server.accept()
        while True:
            try:
                #先接受报头
                header = conn.recv(4)
                #解析报头,获取字典长度
                header_len = struct.unpack('i', header)[0]
                #接收字典
                header_bytes = conn.recv(header_len)
                #将字节格式字典装换为字符串
                header_dic = json.loads(header_bytes.decode('utf-8'))
                print(header_dic)
                #循环接收文件 存储到本地
                file_size = header_dic.get('file_size')  #文件的长度
                file_name = header_dic.get('file_name')  #文件的名称
                recv_size = 0 #当前接收到的文件长度
                #文件操作
                with open(file_name,'wb') as f:
                    #循环接收数据
                    while recv_size<file_size:
                        data = conn.recv(1024)
                        f.write(data)
                        recv_size += len(data)
                    print(header_dic.get('msg'))
            except ConnectionResetError:
                break
        conn.close()
    
    
    #存在问题,无法解决  struct.error: unpack requires a buffer of 4 bytes
    
    
    客户端
    
    import socket
    import os
    import json
    import struct
    
    
    client = socket.socket()
    client.connect(('127.0.0.1', 8082))
    
    #文件大小
    file_size = os.path.getsize(r'D:学习python上课相关day32代码day321 上节课复习.mp4')
    #文件重新命名
    file_name = '上传文件.mp4'
    
    #定义一个字典
    dic = {
        'file_name':file_name,
        'file_size':file_size,
        'msg':'上传成功!'
    }
    
    #将字典序列化后编码为字节
    data_bytes = json.dumps(dic).encode('utf-8')
    
    #制作字典的报头
    header = struct.pack('i', len(data_bytes))
    
    #发送报头
    client.send(header)
    
    #发送字典
    client.send(data_bytes)
    
    #发送真实数据(上传的文件)
    with open(r'D:学习python上课相关day32代码day321 上节课复习.mp4','rb') as f:
        for line in f:
            client.send(line)
    

     

    二、UDP协议
    
    1.udp协议客户端允许发空
    2.udp协议不会粘包
    3.udp协议服务端不存在的情况下,客户端照样不会报错
    4.udp协议支持并发
    
    UDP叫数据报协议,意味着发消息都带有数据报头
    udp的server不需要就行监听也不需要建立连接
    在启动服务之后只能被动的等待客户端发送消息过来,客户端发送消息的时候,要带上服务端的地址
    服务端在回复消息的时候,也需要带上客户端的地址
    
    
    服务端:
    
    import socket
    
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1',8083 ))
    
    while True: #服务端需要始终运行
        data,addr = server.recvfrom(1024)
        print(data,addr) #b'hello' ('127.0.0.1', 54457)
        #data是接收的数据,addr是客户端的地址
        server.sendto(data.upper(),addr)
        #将数据发送过去,同时需要加上客户端的地址
    
    
    客户端:
    
    import socket
    
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_addr = ('127.0.0.1', 8083)
    client.sendto(b'hello', server_addr)
    #发送数据,需要加上接收端的地址
    msg,addr = client.recvfrom(1024)
    #msg是接收的数据,addr是发送方的地址
    print(msg,addr) #b'HELLO' ('127.0.0.1', 8083)
    
    udp协议补充点:
    
            1、无链接,类似于发短信,发了就行对方爱回不回,没有任何关系。
            2、将服务端关了,客户端起起来照样能够发数据。因为不需要考虑服务端能不能收到。
    

      

    三、基于UDP实现简单版本的qq
    
    服务端:
    
    import socket
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1', 8086))
    
    while True:
        data,addr = server.recvfrom(1024)
        print(data.decode('utf-8'))
        data = input('>>>:').encode('utf-8')   #angel
        server.sendto(data,addr)
    
    
    存在多个客户端:
    
    客户端1:
    
    import socket
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1', 8086))
    
    while True:
        data,addr = server.recvfrom(1024)
        print(data.decode('utf-8'))
        data = input('>>>:').encode('utf-8')      #hello
        server.sendto(data,addr)
    
    客户端2:
    
    import socket
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_addr = ('127.0.0.1', 8086)
    
    while True:
        data = input('>>>:')                 #逼格
        data = '来自客户2的消息:%s' %data
        client.sendto(data.encode('utf-8'),server_addr)
        data,addr = client.recvfrom(1024)
        print(data,addr)
    
    
    当启动服务端,启动客户端1后,在客户端1里输入数据,服务端会有响应,再在服务端输入数据,客户端2输入的数据会与服务端响应。
    
    
    来自客户1的消息:hello
    >>>:angel
    来自客户2的消息:逼格
    
    
    小点补充:
                   windows电脑和max电脑的时间同步功能,其实就是基于udp朝windows,max服务器发送请求获取标准时间。
        
        
    

      

    四、SocketServer 模块  (可以让tcp也支持并发)
    
    
    TCP:
        
    服务端:
        import socketserver
    class Base(socketserver.BaseRequestHandler):
        def handle(self):            此处的方法是固定的,不然就会报错!!!   用别人的模块,只能按照别人的方法去写。
            #通信循环
            while True:
                try:
                    data = self.request.recv(1024)  #收消息
                    #self.request相当于通道conn
                    print(data)
                    self.request.send(data.upper()) #发消息
                except ConnectionResetError:
                    break
    
    
    if __name__ == "__main__":
        server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080),Base)
        #socketserver.ThreadingTCPServer(('127.0.0.1') 为建立连接,后者的Base为一个类
        server.serve_forever()   #服务端永久工作
    
    客户端:
    
    import socket
    
    client = socket.socket()
    client.connect(('127.0.0.1', 8080))
    while True:
        client.send(b'hello')
        data = client.recv(1024)
        print(data)
    
    
    
    对UDP同样适用
    
    服务端:
    
    import time
    import socketserver
    
    class Base(socketserver.BaseRequestHandler):
        def handle(self):
            #通信循环
            while True:
                data,sock = self.request   #data是接收的数据,sock是套接字对象
                print(data,sock)    #此处的sock不只是一个地址
    #b'hello' <socket.socket fd=224, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>
                time.sleep(1)
                sock.sendto(data.upper(),self.client_address)  #self.client_address 客户端地址
    
    if __name__ == '__main__':
        server = socketserver.ThreadingUDPServer (('127.0.0.1', 8080),Base)
        server.serve_forever()
    
    
    客户端:
    
    import time
    import socket
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_addr = ('127.0.0.1', 8080)
    while True:
        client.sendto(b'hello',server_addr)
        data,addr = client.recvfrom(1024)
        print(data,addr) #b'HELLO' ('127.0.0.1', 8080)
        time.sleep(1)
    

     

    SocketServer  模块补充

      

    基于tcp的socketserver我们自己定义的类中的

    1.   self.server即套接字对象
    2.   self.request即一个链接
    3.   self.client_address即客户端地址

    基于udp的socketserver我们自己定义的类中的

    1.   self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)
    2.   self.client_address即客户端地址
              1、能够实现并发效果
                            并发:看起来像同时运行就称为并发   并行:同时运行   注:单核计算机无法实现并行
              2、udp在使用的时候,多个客户端需要存在一些io操作,不然容易卡死
    

      

    并发编程:
    
    后续补充!
    

      

     

      

     

  • 相关阅读:
    linux下一个网卡配置多个ip(转)
    实验室生活:第一个月
    关闭或开启Linux上的iptables防火墙,SSH端口(转)
    TcpTrace追踪远程服务器的soap信息
    我的mysql学习笔记(1)mysql的安装
    大型网站架构演变和知识体系[转载]
    ms sql一些有用的语句
    我的mysql学习笔记(2)mysql基本的命令
    SQL Server 2008 R2数据库镜像部署[转]
    C++ 自定义动态数组模板
  • 原文地址:https://www.cnblogs.com/changwenjun-666/p/10815126.html
Copyright © 2011-2022 走看看