• 《Python》网络编程之验证客户端连接的合法性、socketserver模块


    一、socket的更多方法介绍

    # 服务端套接字函数
    s.bind()    # 绑定(主机,端口号)到套接字
    s.listen()  # 开始TCP监听
    s.accept()  # 被动接受TCP客户的连接,(阻塞式)等待连接的到来
    
    # 客户端套接字函数
    s.connect()     # 主动初始化TCP服务器连接
    s.connect_ex()  # connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
    
    # 公共用途的套接字函数
    s.recv()         # 接收TCP数据
    s.send()         # 发送TCP数据
    s.sendall()      # 发送TCP数据
    s.recvfrom()     # 接收UDP数据
    s.sendto()       # 发送UDP数据
    s.getpeername()  # 连接到当前套接字的远端的地址
    s.getsockname()  # 当前套接字的地址
    s.getsockopt()   # 返回指定套接字的参数
    s.setsockopt()   # 设置指定套接字的参数
    s.close()        # 关闭套接字
    
    # 面向锁的套接字方法
    s.setblocking()  # 设置套接字的阻塞与非阻塞模式
    s.settimeout()   # 设置阻塞套接字操作的超时时间
    s.gettimeout()   # 得到阻塞套接字操作的超时时间
    
    # 面向文件的套接字的函数
    s.fileno()       # 套接字的文件描述符
    s.makefile()     # 创建一个与该套接字相关的文件
    官方文档对socket模块下的socket.send()和socket.sendall()解释如下:
    
    socket.send(string[, flags])
    Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Returns the number of bytes sent. Applications are responsible for checking that all data has been sent; if only some of the data was transmitted, the application needs to attempt delivery of the remaining data.
    
    send()的返回值是发送的字节数量,这个数量值可能小于要发送的string的字节数,也就是说可能无法发送string中所有的数据。如果有错误则会抛出异常。
    
    –
    
    socket.sendall(string[, flags])
    Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Unlike send(), this method continues to send data from string until either all data has been sent or an error occurs. None is returned on success. On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent.
    
    尝试发送string的所有数据,成功则返回None,失败则抛出异常。
    
    故,下面两段代码是等价的:
    
    #sock.sendall('Hello world
    ')
    
    #buffer = 'Hello world
    '
    #while buffer:
    #    bytes = sock.send(buffer)
    #    buffer = buffer[bytes:]
    send和sendall方法

     

    二、验证客户端链接的合法性

      如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加盐的方式来实现

      server端:

    import os
    import hmac
    import socket
    
    def auth(conn):
        msg = os.urandom(32)    # 生成一个随机的字符串
        print(msg, len(msg))    # 32位
        conn.send(msg)  # 发送到client端
        result = hmac.new(secret_key, msg)  # 处理这个随机字符串,得到一个结果
        client_digest = conn.recv(1024)     # 接收client端处理的结果
        if result.hexdigest() == client_digest.decode('utf-8'):
            print('是合法的连接')     # 对比成功可以继续通讯
            return True
        else:
            print('不合法的连接')     # 不成功 close
            return False
    
    secret_key = b'alex_s'   # 相当于'盐'
    sk = socket.socket()
    sk.bind(('127.0.0.1', 9000))
    sk.listen()
    conn, addr = sk.accept()
    if auth(conn):
        print(conn.recv(1024))
        # 正常的和client端进行沟通
        conn.close()
    else:
        conn.close()
    
    sk.close()

      client端:

    import hmac
    import socket
    
    def auth(sk):
        msg = sk.recv(32)   # 接收随机字符串
        result = hmac.new(key, msg) # 处理这个随机字符串
        res = result.hexdigest()
        sk.send(res.encode('utf-8'))
    
    key = b'alex_s' # '盐',要与server端的一致
    sk = socket.socket()
    sk.connect(('127.0.0.1', 9000))
    auth(sk)    # 调用函数进行验证
    # 验证成功就可以通讯了
    sk.send(b'hello')
    
    sk.close()

    三、socketserver模块

      server端:

    import socketserver
    # tcp协议的server端就不需要导入socket
    class Myserver(socketserver.BaseRequestHandler):
        def handle(self):
            conn = self.request
            while 1:
                conn.send(b'hello')
                print(conn.recv(1024))
    
    # 创建一个server, 将服务地址绑定到127.0.0.1  9000
    server = socketserver.ThreadingTCPServer(('127.0.0.1', 9000), Myserver)
    # 让server永远运行下去,除非强制停止程序
    server.serve_forever()

      client端:

    import socket
    
    sk = socket.socket()
    sk.connect(('127.0.0.1', 9000))
    while 1:
        ret = sk.recv(1024)
        print(ret)
        sk.send(b'byebye')
    sk.close()
  • 相关阅读:
    常用地址
    三步搭建Spring Cloud 服务注册
    Java判断两个时间段是否有交集
    CentOS-7下安装docker
    linux 版菱形
    《少林问道》
    Linux下安装Nginx详细图解教程
    测试
    CentOS修改主机名和主机表
    虚拟机中CentOS配置静态网络
  • 原文地址:https://www.cnblogs.com/yzh2857/p/9663604.html
Copyright © 2020-2023  润新知