zoukankan      html  css  js  c++  java
  • python全栈开发_day32_粘包分析,socketserver和多道技术

    为什么会出现粘包现象

    """
    首先只有在TCP协议中才会出现粘包现象,因为TCP协议是流式协议
    它的特点是将数据量小并且时间间隔比较短的数据一次性打包发送出去
    本质其实还是因为我们不知道需要接收的数据的长短
    """
    # 如何解决粘包问题?
    # 1 发送数据直接先告诉对方数据量的大小
    # 2 利用struct模块定制我们自己的消息传输协议

    socket发送大文件示例

    # 客户端
    import struct
    import json
    import socket
    import os

    client = socket.socket()
    client.connect(('127.0.0.1', 8080))

    file_size = os.path.getsize(r'/Users/jiboyuan/PycharmProjects/aboutsocket/10 解决粘包问题终极版.mp4')
    file_path = r'/Users/jiboyuan/PycharmProjects/aboutsocket/10 解决粘包问题终极版.mp4'
    data_dic = {
       'file_name': '澳门最大线上赌场开业啦.mp4',
       'file_size': file_size
    }
    header_json = json.dumps(data_dic)
    header_bytes = header_json.encode('utf-8')
    # 制作字典的报头
    header = struct.pack('i', len(header_bytes))
    # 发送报头
    client.send(header)
    # 发字典数据
    client.send(header_bytes)
    # 打开文件发送文件数据
    with open(file_path,'rb') as f:
       for line in f:
           client.send(line)

    # 服务端
    import socket
    import json
    import struct

    server = socket.socket()
    server.bind(('127.0.0.1', 8080))
    server.listen(5)

    while True:
       conn, addr = server.accept()
       while True:
           try:
               header = conn.recv(4)
               if len(header) == 0:break
               dic_len = struct.unpack('i', header)[0]

               real_dic = json.loads(conn.recv(dic_len).decode('utf-8'))
               print(real_dic)
               file_name = real_dic.get('file_name')
               file_size = real_dic.get('file_size')
               recv_size = 0
               with open(file_name, 'wb') as f:
                   while recv_size < file_size:
                       recv_data = conn.recv(1024)
                       f.write(recv_data)
                       recv_size += len(recv_data)
           except ConnectionResetError:
               break

    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', 8080))

    msg, addr = server.recvfrom(1024)
    print(msg.decode('utf-8'))
    server.sendto(b'hello', addr)

    server.close()

    #客户端
    import socket

    client = socket.socket(type=socket.SOCK_DGRAM)
    server_addr = ('127.0.0.1', 8080)

    client.sendto(b'hello server baby!', server_addr)
    msg, addr = client.recvfrom(1024)
    print(msg, addr)


    # udp特点 >>> 无链接,类似于发短信,发了就行对方爱回不回,没有任何关系
    # 将服务端关了,客户端起起来照样能够发数据。因为不需要考虑服务端能不能收到

    # 验证udp协议有无粘包问题
    import socket
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1',8080))
    print(server.recvfrom(1024))
    print(server.recvfrom(1024))
    print(server.recvfrom(1024))

    import socket
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_addr = ('127.0.0.1',8080)
    client.sendto(b'hello',server_addr)
    client.sendto(b'hello',server_addr)
    client.sendto(b'hello',server_addr)

    基于UDP实现简易版本的qq

    # 服务端
    import socket

    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1', 8080))
    while True:
       msg, addr = server.recvfrom(1024)
       print(addr)
       print(msg.decode('utf-8'))
       info = input('>>>:').encode('utf-8')
       server.sendto(info, addr)

    server.close()

    # 多个客户端
    import socket

    client = socket.socket(type=socket.SOCK_DGRAM)
    server_addr = ('127.0.0.1', 8080)

    while True:
       info = input('>>>:')
       info = ('来自客户端1的消息:%s'%info).encode('utf-8')  # 改中文备注即可
       client.sendto(info, server_addr)
       msg, addr = client.recvfrom(1024)
       print(msg.decode('utf-8'), addr)

    client.close()

    小知识点补充:

    windows电脑和max电脑的时间同步功能,其实就是基于udp朝windows,max服务器发送请求获取标准时间

     

    总结:

    TCP协议就类似于打电话

    UDP协议就类似于发短信

     

    SocketServer模块介绍(让tcp也能支持并发)

    并发

    # TCP socketserver使用
    import socketserver
    class MyTcpServer(socketserver.BaseRequestHandler):
       def handle(self):
           while True:
               try:
                   data = self.request.recv(1024)  # 对于tcp,self.request相当于conn对象
                   if len(data) == 0:break
                   print(data)
                   self.request.send(data.upper())
               except ConnectionResetError:
                   break
    if __name__ == '__main__':
       server = socketserver.ThreadingTCPServer(('127.0.0.1',8081),MyTcpServer)
       server.serve_forever()

    # UDP socketserver使用
    import socketserver


    class MyUdpServer(socketserver.BaseRequestHandler):
       def handle(self):
           while True:
               data, sock = self.request
               print(data)
               sock.sendto(data.upper(), self.client_address)


    if __name__ == '__main__':
       server = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyUdpServer)
       server.serve_forever()

    并发编程

    操作系统的发展史

    输入输出设备>>>:IO操作即(input和output)

    • 手工操作穿孔卡片

    • 批处理(磁带)

    • 脱机批处理系统

    一步步的优化,其实都是在提高计算机CPU利用率的问题(问题在于时串行并且没有空间上的复用)

    多道技术的产生

    解决cpu在执行程序,遇到io时,不干活的情况

    串行:一个程序完完整整的运行完毕,才能运行下一个程序

    并发:看上去像同时运行

     

    多道技术:

    • 空间上的复用(多个程序共一套硬件设备,它是多道技术实现时间上的复用的基础,不然还要去硬盘读数据)

    • 时间上的复用(单个cpu的电脑上,起多个应用程序。cpu快速切换,给人的感觉是同时运行)

    • 一个任务占用cpu时间过长或被操作系统强行剥夺走cpu的执行权限(比起串行效率反而降低)

    • 一个任务执行过程中遇到io操作,也会被操作系统强行剥夺走cpu的执行权限(比起串行效率提高)

  • 相关阅读:
    关于 No buffer space available (maximum connections reached?): connect 的处理
    Cron 表达式
    Hudson 打包部署到Was上特别慢
    JAVA jar 参数
    CentOS 6 UNEXPECTED INCONSISTENCY RUN fsck MANUALLY
    SSH 连接很慢
    解决libc.so.6: version `GLIBC_2.14&#39; not found问题
    Maven 基本参数
    Shc 应用
    JAVA 关于JNI本地库加载
  • 原文地址:https://www.cnblogs.com/xuxingping/p/10853824.html
Copyright © 2011-2022 走看看