• day 27


    subprocess模块

    • 可以帮你通过代码执行操作系统的终端命令
    • 并返回终端执行命令后的结果

    粘包问题

    服务端第一次发送的数据,客户端无法精确一次性接收完毕。

    下一次发送的数据与上一次数据粘在一起了。

    • 无法预测对方需要接受的数据大小长度。
    • 多次连续发送数据量小、并且时间隔短的数据一次性打包发送。

    TCP协议特性

    TCP是一个流式协议,会将多次连续发送数据量小、并且时间间隔短的数据一次性打包发送。

    解决粘包问题

    struct模块

    必须先定义报头,发送报头,再发送真实数据

    # 服务端
    import socket
    import subprocess
    import struct
    
    
    
    server = socket.socket()
    
    server.bind(
        ('127.0.0.2', 9999)
    )
    
    server.listen(7)
    
    while True:
        conn, addr = server.accept()
    
        while True:
            try:
                # recv的数据是从内存中获取
                cmd =conn.recv(1024).decode('utf_8')
    
                if cmd == 'q':
                    break
    
                if len(cmd) == 0:
                    continue
    
                print(cmd)
    
                # 执行cmd命令
                obj = subprocess.Popen(
                    cmd,
                    shell=True,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE
                )
    
                # 接收终端返回的数据
                result = obj.stdout.read() + obj.stderr.read()
    
                # 打包压缩,获取报头
                headers = struct.pack('i', len(result))
    
                # 先发送头部
                conn .send(headers)
    
                # 再发送真实数据
                conn.send(result)
    
    
            except Exception as e:
                print(e)
                break
        conn.close()
    
    # 客户端
    import socket
    import struct
    
    
    client = socket.socket()
    
    client.connect(
        ('127.0.0.2', 9999)
    )
    
    while True:
        cmd = input('》》》:')     # dir
        client.send(cmd.encode('utf-8'))
    
        if cmd == 'q':
            break
    
        # 先获取数据报头
        headers = client.recv(4)
    
        # 解包,或者真实数据长度
        data_len = struct.unpack('i', headers)[0]   # (len, )
    
        # 接收真实数据长度
        data = client.recv(data_len)
    
        print(data.decode('gbk'))
    
    client.close()
    

    上传大文件

    客户端往服务端上传大文件

    QQ聊天室

    # 服务端
    import socket
    server = socket.socket(type = socket.SOCK_DGRAM)
    
    server.bind(
        ('127.0.0.1',9507)
    )
    while True:
        #服务端接收客户端穿过来的消息
        msg,addr = server.recvfrom(1024)
        msg1,addr1 = server.recvfrom(1024)
        msg2,addr2 = server.recvfrom(1024)
        
        print(addr)
        print(addr1)
        print(addr2)
        
        print(msg.decode('utf-8'))
        print(msg1.decode('utf-8'))
        print(msg2.decode('utf-8'))
        
        #服务端往客户端发送消息
        send_msg = input('服务端发送消息:').encode('utf-8')
        server.sendto(send_msg,addr)
        server.sendto(send_msg,addr1)
        server.sendto(send_msg,addr2)
    
    # 客户端
    import socket
    client = socket.socket(type = socket.SOCK_DGRAM)
    
    server_ip_port = ('127.0.0.1'9507)
    while True:
        send_msg = input('客户端1').encode('utf-8')
        
        #发送消息必须要加上对方地址
        client.sendto(send_msg,server_ip_port)
        #能接收任何人的消息
        msg=client.recv(1024)
        print(msg.decode('utf-8'))
    

    UDP

    UDP是一种传输协议

    • 不需要建立双向通道

    • 不会粘包

    • 客户端给服务端发送数据, 不需要等待服务器返回接收成功

    • 数据容易丢失,数据不安全

    TCP:就好比在打电话

    UDP:就好比在发短信

    SocketServer

    python内置模块, 可以简化socket套接字服务端的代码。

    • 简化TCP与UDP的服务端代码
    • 必须要创建一个类
    import sockerserver
    
    # 定义类
    # TCP:必须继承BaseRequestHanlder类
    class MyTcpServer(socketserver,BaseRequestHandler):
        # 必须重写父类的handle
        def handle(self):
            
            # 1.接收消息
            data = self.request.recv(1024)
            print(data)
            # 2.给客户端发送消息
            send_msg = input('服务端:').encode('utf-8')
            self.request.send(send_msg)
            
           
    if __name__ == '__main__':
        socketserver.TCPServer.allow_reuse_address = True
        server = socketserver.TCPServer(
        ('127.0.0.1', 6659), MyTCPServer)
        
        # 永久执行服务
        server.serve_forever()
        
    
  • 相关阅读:
    ScrollView反弹效果的实现
    Unity 3D本地公布WebPlayer版时"Failed to download data file"解决方式
    win7休眠的开启与关闭方法命令行操作和图文结合的鼠标操作
    使用Javascript D3创建属于你的涂鸦作品
    android获取自己定义控件位置坐标,屏幕尺寸,标题栏,状态栏高度
    [Python]Use Flask-Admin with PostgreSQL
    [LeetCode] Best Time to Buy and Sell Stock
    spring实战五之Bean的自动检测
    FireBug使用总结
    javascript的window.onload()方法和jQuery的$(document).ready()的对比
  • 原文地址:https://www.cnblogs.com/colacheng0930/p/11700265.html
Copyright © 2020-2023  润新知