zoukankan      html  css  js  c++  java
  • 网络编程(三) 大文件传输与UDP通信

    1.基于TCP协议传输大文件

    可以根据TCP粘包问题的处理方法实现大文件的传输

    上传大文件

     1 import socket
     2 import os
     3 import struct
     4 import json
     5 
     6 client = socket.socket()
     7 client.connect(('127.0.0.1',8080))
     8 
     9 while True:
    10     MOVIE_DIR = r'F:迅雷下载'
    11     movie_list = os.listdir(MOVIE_DIR)
    12     for i,movie in enumerate(movie_list,1):
    13         print(i,movie)
    14     choice = input('>>>:').strip()
    15     if not choice.isdigit():
    16         print('请输入数字')
    17         continue
    18     choice = int(choice)-1
    19     if choice not in range(0,len(movie_list)):
    20         print('请输入正确的编号')
    21         continue
    22     movie_name = movie_list[choice]
    23     movie_path = os.path.join(MOVIE_DIR,movie_name)
    24     size = os.path.getsize(movie_path)
    25     # 生成一个字典
    26     d = {'name':movie_name,'size':size,'path':movie_path}
    27     json_d = json.dumps(d)
    28     # 生成一个字典报头
    29     header = struct.pack('i',len(json_d))
    30     # 发送字典报头
    31     client.send(header)
    32     # 发送字典
    33     client.send(json_d.encode('utf-8'))
    34     # 发送真实数据
    35     with open(movie_path,'rb')as f:
    36         for line in f:
    37             client.send(line)
    38     print('上传成功')
    客户端
     1 import socket
     2 import struct
     3 import json
     4 import os
     5 
     6 server = socket.socket()
     7 server.bind(('127.0.0.1',8080))
     8 server.listen(5)
     9 
    10 while True:
    11     conn, addr = server.accept()
    12     while True:
    13         try:
    14             # 接收报头
    15             header = conn.recv(4)
    16             dict_len = struct.unpack('i',header)[0]
    17             # 接收字典
    18             d = conn.recv(dict_len).decode('utf-8')
    19             dict = json.loads(d)
    20             # 字典中取出数据
    21             movie_name = dict.get('name')
    22             movie_size = dict.get('size')
    23             save_path = os.path.join(movie_name)
    24             recv_size = 0
    25             # 接收真实数据
    26             with open(save_path,'wb')as f:
    27                 while recv_size < movie_size:
    28                     data = conn.recv(1024000000)
    29                     f.write(data)
    30                     recv_size += len(data)
    31                     c = recv_size / movie_size
    32                     d = "%.2f%%" % (c * 100)
    33                     print(d)
    34             print('接收上传完毕')
    35         except ConnectionResetError as e:
    36             print(e)
    37             break
    38     conn.close()
    服务端

    下载大文件

     1 import socket
     2 import json
     3 import struct
     4 
     5 client = socket.socket()
     6 client.connect(('127.0.0.1',8080))
     7 
     8 while True:
     9     # 接收列表的报头
    10     list_header = client.recv(4)
    11     # 解包获取列表的长度
    12     list_len = struct.unpack('i',list_header)[0]
    13     # 接收列表
    14     movie_json = client.recv(list_len).decode('utf-8')
    15     movie_list = json.loads(movie_json)
    16     for i,movie in enumerate(movie_list,1):
    17         print(i,movie)
    18     choice = input('>>>:').strip()
    19     if not choice.isdigit():
    20         print('请输入数字')
    21         continue
    22     choice = int(choice) - 1
    23     if choice not in range(0,len(movie_list)):
    24         print('请输入正确的编号')
    25         continue
    26     # 发送选择
    27     client.send(str(choice).encode('utf-8'))
    28     # 接收报头
    29     dict_header = client.recv(4)
    30     # 解包获取字典长度
    31     dict_len = struct.unpack('i',dict_header)[0]
    32     # 接收字典
    33     d = client.recv(dict_len).decode('utf-8')
    34     movie_dict = json.loads(d)
    35     # 获取字典中的信息
    36     movie_name = movie_dict.get('name')
    37     movie_size = movie_dict.get('size')
    38     recv_size = 0
    39     # 接收真实数据
    40     with open(movie_name,'wb')as f:
    41         while recv_size < movie_size:
    42             data = client.recv(1024)
    43             f.write(data)
    44             recv_size += len(data)
    45             c = recv_size/movie_size
    46             d = "%.2f%%" % (c * 100)
    47             print(d)
    48     print('下载成功')
    客户端
     1 import json
     2 import socket
     3 import os
     4 import struct
     5 
     6 
     7 server = socket.socket()
     8 server.bind(('127.0.0.1',8080))
     9 server.listen()
    10 
    11 while True:
    12     conn, addr = server.accept()
    13     while True:
    14         try:
    15             MOVIE_DIR = r'F:迅雷下载'
    16             # 生成电影列表
    17             movie_list = os.listdir(MOVIE_DIR)
    18             movie_json = json.dumps(movie_list)
    19             list_header = struct.pack('i',len(movie_json))
    20             # 发送列表的报头
    21             conn.send(list_header)
    22             # 发送列表
    23             conn.send(movie_json.encode('utf-8'))
    24             # 接收选择
    25             choice = conn.recv(1024).decode('utf-8')
    26             choice = int(choice)
    27             movie_name = movie_list[choice]
    28             # 获取电影的信息,生成字典
    29             movie_path = os.path.join(MOVIE_DIR,movie_name)
    30             size = os.path.getsize(movie_path)
    31             d = {'name':movie_name,'size':size}
    32             # 制作电影的报头
    33             dict = json.dumps(d)
    34             dict_header = struct.pack('i',len(dict))
    35             # 发送报头
    36             conn.send(dict_header)
    37             # 发送字典
    38             conn.send(dict.encode('utf-8'))
    39             # 发送真实数据
    40             with open(movie_path,'rb')as f:
    41                 for line in f:
    42                     conn.send(line)
    43             print('发送完成')
    44         except ConnectionResetError as e:
    45             print(e)
    46             break
    47     conn.close()
    服务端

    2.异常处理

    什么是异常

      异常就是程序在运行过程中出现了不可预知的错误

      并且该错误没有对应的处理机制,会以异常的形式表现出来

      造成的影响就是整个程序无法再正常运行

    异常的结构

      1.异常的类型:NAMEERROR

      2.异常的信息:name 'fdsdfsdf' is not defined

      3.异常的位置:Traceback (most recent call last):后面跟的就是出现异常的位置,点击就能自动找到该位置

    异常的种类,分为两大类

      1.语法错误:

        这种是运行程序立刻就能发现的,发现之后可以立刻解决

      2.逻辑错误

        这种错误一眼并不能看出来,针对这种错误,我们可以使用异常处理机制来捕获

    常见的错误类型: 

      NAMERROR 名字错误
      SyntaxError 语法错误
      KeyError 键不存在
      ValueError 值错误
      IndexError 索引错误

    如何避免

      异常处理:

        在会出现异常代码块上方try一下.注意:try内部的代码块越少越好

      语法:

    1 try:
    2     # 可能出现错误的代码块
    3 except 错误的类型 as e:  # 将错误的信息赋值给变量e
    4     # 出错之后的代码块

    万能异常处理Exception和BaseException

     1 # 两个万能异常处理Exception和BaseException
     2 try:
     3     l = [1,2,3]
     4     l[123]
     5 except Exception as e:
     6     print(e)
     7     print('被我处理掉了')
     8 
     9 try:
    10     d = {'name':'sxc'}
    11     d['pwd']
    12 except BaseException as e:
    13     print(e)
    14     print('被我处理掉了')

    异常处理的else和finally

     1 # else和finally
     2 try:
     3     d = {'name':'sxc'}
     4     d['name']
     5 except BaseException as e:
     6     print(e)
     7     print('被我处理掉了')
     8 else:
     9     print('没有出错就会走else')
    10 finally:
    11     print('不管有没有出错都会走finally')

    主动抛出异常

    1 # 主动抛出异常
    2 if 1 > 2:  # 异常判断条件
    3     pass
    4 else:
    5     raise TypeError('不存在的')  # raise + TypeError + 异常信息

    断言

    1 # 断言,预言
    2 l = [1,2,3]
    3 assert l[0] < 0

    自定义异常

    1 # 自定义异常
    2 class MyError(BaseException):
    3     def __init__(self,msg):
    4         super().__init__()
    5         self.msg = msg
    6     def __str__(self):
    7         return '<%s>' %self.msg
    8 
    9 raise MyError('自定义的异常')

    3.基于UDP通信的socket

      又称数据包协议,UDP协议是无连接的,启动之后可以直接接收消息,不需要提前建立连接,类似于发短信

    UDP通信socket的简单使用

     1 import socket
     2 import time
     3 
     4 client = socket.socket(type=socket.SOCK_DGRAM)
     5 server_addr = ('127.0.0.1',8080)
     6 
     7 while True:
     8     client.sendto(b'hello',server_addr)
     9     data,addr = client.recvfrom(1024)
    10     print(data)
    11     print(addr)
    客户端
     1 import socket
     2 
     3 server = socket.socket(type=socket.SOCK_DGRAM)
     4 server.bind(('127.0.0.1',8080))
     5 # 面向连接的不需要半连接池,也不需要建立双向通道
     6 while True:
     7     data, addr = server.recvfrom(1024)
     8     print(data)
     9     print(addr)
    10     server.sendto(data.upper(),addr)
    服务端

    UDP通信和TCP通信的区别

      1.UDP协议允许发空

      2.UDP协议不会粘包

      3.UDP协议服务端不存在的情况下.客户端不会报错

      4.UDP协议支持并发

    基于UDP实现一个简易版本的QQ

     1 import socket
     2 
     3 server = socket.socket(type=socket.SOCK_DGRAM)
     4 server.bind(('127.0.0.1',8080))
     5 
     6 while True:
     7     data ,addr = server.recvfrom(1024)
     8     print(data.decode('utf-8'))
     9     msg = input('>>>:')
    10     server.sendto(msg.encode('utf-8'),addr)
    服务端
     1 import socket
     2 
     3 client = socket.socket(type=socket.SOCK_DGRAM)
     4 server_addr = ('127.0.0.1',8080)
     5 
     6 while True:
     7     msg = input('>>>:')
     8     msg1 = '来自客户端1的消息%s'%msg
     9     client.sendto(msg1.encode('utf-8'),server_addr)
    10     data,addr = client.recvfrom(1024)
    11     print(data.decode('utf-8'))
    客户端

    如需要多个客户通信,只要多开几个客户端就行了

    4.SocketServer模块

    可以实现TCP/UDP并发通信

    TCP并发通信

    1 import socket
    2 
    3 client = socket.socket()
    4 client.connect(('127.0.0.1',8080))
    5 
    6 while True:
    7     client.send(b'hello')
    8     data = client.recv(1024)
    9     print(data.decode('utf-8'))
    客户端
     1 import socketserver
     2 
     3 class MyServer(socketserver.BaseRequestHandler):
     4     def handle(self):
     5         while True:
     6             data = self.request.recv(1024)
     7             print(self.client_address)  # 客户端地址
     8             print(data.decode('utf-8'))
     9             self.request.send(data.upper())
    10 
    11 
    12 if __name__ == '__main__':
    13     # 当有客户端来连接会自动交给自定义类中的handle方法处理
    14     server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer)  # 创建一个基于TCP的对象
    15     server.serve_forever()  # 启动这个对象
    服务端

    UDP并发通信

     1 import socket
     2 import time
     3 
     4 client = socket.socket(type=socket.SOCK_DGRAM)
     5 server_addr = ('127.0.0.1',8080)
     6 
     7 while True:
     8     client.sendto(b'hello',server_addr)
     9     data,addr = client.recvfrom(1024)
    10     print(data.decode('utf-8'),addr)
    11     time.sleep(1)
    客户端
     1 import socketserver
     2 
     3 class MyServer(socketserver.BaseRequestHandler):
     4     def handle(self):
     5         while True:
     6             data,sock = self.request
     7             print(self.client_address)  # 客户端地址
     8             print(data.decode('utf-8'))
     9             sock.sendto(data.upper(),self.client_address)
    10 
    11 
    12 if __name__ == '__main__':
    13     # 当有客户端来连接会自动交给自定义类中的handle方法处理
    14     server = socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyServer)  # 创建一个基于UDP的对象
    15     server.serve_forever()  # 启动这个对象
    服务端

     29

  • 相关阅读:
    Android面试题
    java面试题大全
    关于索引的sql语句优化之降龙十八掌
    java动态代理的实现
    java动态代理
    进程与线程
    SqlServer聚合函数
    2015年创业中遇到的技术问题:21-30
    hadoop集群ambari搭建(2)之制作hadoop本地源
    Android录屏命令、Android录Gif、Android录视频
  • 原文地址:https://www.cnblogs.com/sxchen/p/11323456.html
Copyright © 2011-2022 走看看