• 基于TCP协议的socket套接字编程


    基于TCP协议的socket套接字编程

    服务端

    import socket
    
    # 1. 符合TCP协议的手机
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # TCP
    
    # 2. 绑定手机号 110
    server.bind(('127.0.0.1', 8000))  # 127.0.0.1代表本地
    # server.bind(('192.168.11.210',8000))  # 127.0.0.1代表本地
    
    server.listen(5)  # 半连接池
    
    # 3. 等待客户端连接
    print('start...')
    # 链接循环
    
    
    while True:
        # 通信循环
        conn, client_addr = server.accept()
        while True:
            try:
                # 4. 收到消息receive
                data = conn.recv(1024)
                print(data)
    
                # 5. 回消息
                conn.send(data.upper())
            except ConnectionAbortedError:
                continue
            except ConnectionResetError:
                break
    

    客户端

    import socket
    
    # 1. 创建符合TCp协议的手机
    client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    # 2. 拨号
    client.connect(('127.0.0.1',8000))
    
    while True:
        msg = input('please enter your msg')  # dir
        # 3. 发送消息
        client.send(msg.encode('utf8'))
    
        # 4. 接收消息
        data = client.recv(1024)
        print(data)
    

    模拟ssh远程执行命令

    在客户端处模拟ssh发送命令,服务端通过subprocess执行该命令,然后返回命令的结果

    服务端

    import socket
    import subprocess
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    server.bind(('192.168.11.210', 8000))
    server.listen(5)
    
    print('start...')
    while True:
        conn, client_addr = server.accept()
        print(client_addr)
    
        while True:
            try:
                cmd = conn.recv(1024)  # dir
                print(cmd)
    
                # 帮你执行cmd命令,然后把执行结果保存到管道里
                pipeline = subprocess.Popen(cmd.decode('utf8'),
                                            shell=True,
                                            stderr=subprocess.PIPE,
                                            stdout=subprocess.PIPE)
    
                stderr = pipeline.stderr.read()
                stdout = pipeline.stdout.read()
    
                conn.send(stderr)
                conn.send(stdout)
    
            except ConnectionResetError:
                break
    

    客户端

    import socket
    
    # 1. 创建符合TCp协议的手机
    client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    # 2. 拨号
    client.connect(('192.168.11.210',8000))
    
    while True:
        msg = input('please enter your msg')  # dir
        # 3. 发送消息
        client.send(msg.encode('utf8'))
    
        # 4. 接收消息
        data = client.recv(10)
        print(data.decode('gbk'))
    

    粘包问题

    TCP发送数据的四种情况

    123-粘包问题-粘包可能.png

    假如客户端分别发送了两个数据包D1和D2给服务端,由于服务端一次读取到的字节是不确定的,故可能存在以下4种情况:

    1.服务端分两次读取到了两个独立的数据包,分别是D1和D2,没有粘包和拆包;

    2.服务端一次接收到了两个数据包,D1和D2粘合在一起,被称为TCP粘包;

    3.服务端分两次读取到了两个数据包,第一次读取到了完整的D1包和D2包的内容,第二次读取到了D2包的剩余内容,这被称为TCP拆包;

    4.服务端分两次读取到了两个数据包,第一次读取到了D1包的部分内容D1_1,第二次读取到了D1包的剩余内容D1_2和D2包的整包。

    特例:如果此时服务端TCP接收滑窗非常小,而数据包D1和D2比较大,很有可能会发生第五种可能,即服务端分多次才能将D1和D2包接受完全,期间发生多次拆包。

    注意:只有TCP有粘包现象,UDP永远不会粘包。

    粘包的两种情况

    1.发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据量很小,会合到一起,产生粘包)

    2.接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只是接收了一小部分,服务端下次再接收的时候还是从缓冲区拿上次遗留的数据,产生粘包)

    解决粘包问题

    服务端

    from socket import *
    import subprocess
    import struct
    
    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('127.0.0.1', 8000))
    server.listen(5)
    
    print('start...')
    while True:
        conn, client_addr = server.accept()
        print(conn, client_addr)
    
        while True:
            try:
                cmd = conn.recv(1024)
    
                obj = subprocess.Popen(cmd.decode('utf8'),
                                       shell=True,
                                       stderr=subprocess.PIPE,
                                       stdout=subprocess.PIPE)
    
                stderr = obj.stderr.read()
                stdout = obj.stdout.read()
    
                count_len=len(stderr)+len(stdout)
                guding_bytes=struct.pack('i',count_len)
    
                conn.send(guding_bytes)
                conn.send(stderr+stdout)
            except ConnectionResetError:
                break
    

    客户端

    from socket import *
    import struct
    
    client = socket(AF_INET, SOCK_STREAM)
    client.connect(('127.0.0.1', 8000))
    
    while True:
        cmd = input('please enter your cmd you want>>>')
    
        if len(cmd) == 0: continue
    
        client.send(cmd.encode('utf8'))
    
        # 1. 先收4个字节,这4个字节中包含报头的长度
        header_len = struct.unpack('i', client.recv(4))[0]
    
        # 2. 再接收报头
        header_bytes = client.recv(header_len)
        print(header_bytes.decode('gbk'))
    

    基于UDP协议的socket套接字编程

    服务端

    import socket
    
    server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    server.bind(('127.0.0.1', 8000))
    
    print('start...')
    while True:
        data, client_addr = server.recvfrom(1024)
        print(client_addr)
        print(data)
        server.sendto(data.upper(), client_addr)
    

    客户端

    import socket
    
    client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    while True:
        msg = input('please enter your msg:')
        client.sendto(msg.encode('utf8'), ('127.0.0.1', 8000))
    
        data = client.recvfrom(1024)
        print(data)
    

    基于socketserver实现并发的socket套接字编程

    服务端

    # 同一时刻有多个人在接听
    import socketserver
    import subprocess
    import struct
    
    
    class MyHandler(socketserver.BaseRequestHandler):
        # 通信循环
        def handle(self):
    
            while True:
                try:
                    cmd = self.request.recv(1024)
                    print(cmd)
    
                    pipeline = subprocess.Popen(cmd.decode('utf8'),
                                                shell=True,
                                                stderr=subprocess.PIPE,
                                                stdout=subprocess.PIPE)
    
                    stdout = pipeline.stdout.read()
                    stderr = pipeline.stderr.read()
    
                    count_len = len(stdout) + len(stderr)
                    guding_bytes = struct.pack('i', count_len)
    
                    self.request.send(guding_bytes)  # 4
    
                    self.request.send(stderr + stdout)
    
                except ConnectionResetError:
                    break
    
    
    # 使用socketserver的连接循环(并发),但是使用了自己的通信循环
    # myhandler = MyHandler()
    if __name__ == '__main__':
        server = socketserver.ThreadingTCPServer(('127.0.0.1', 8000), MyHandler, bind_and_activate=True)
        print('start...')
        server.serve_forever()
    
    
  • 相关阅读:
    使用netty实现im聊天
    使用rabbitmq实现集群im聊天服务器消息的路由
    springcloud feign使用
    10万用户一年365天的登录情况如何用redis存储,并快速检索任意时间窗内的活跃用户
    redis的rdb与aof持久化机制
    springcloud-zinpin的安装与使用
    kafka的基本安装与使用
    RabbitMq 实现延时队列-Springboot版本
    RabbitMq 基本命令
    Dcoker 安装 rabbitMq
  • 原文地址:https://www.cnblogs.com/gaohuayan/p/11097491.html
Copyright © 2020-2023  润新知