zoukankan      html  css  js  c++  java
  • Python 第二十九章 socket通信

    socket通信

    socket 套接字

    **socket :一组简化的便于操作的接口**
    应用层通过socket接口传给传输层后面的操作交给操作系统去完成
    是处于应用层与T传输层(TCP/IP)协议通信的抽象层,是一组操作起来非常简单的接口(接收数据)
    此接口接收数据后,交由操作系统
    **为什么存在socket抽象层:**
    直接与操作系统数据交互非常麻烦,繁琐,socket对这些繁琐的操作高度的封装简化
    socket 在Python中就是一个模块,提供的功能:
    找到ip地址Mac地址端口号就能获取到计算机软件的位置
    获取ip地址和端口号就能判断mac地址
    socket 通信先启动服务端,再启动客户端
    

    基于TCP协议的socket简单通信

    服务端

    # 导入socket模块
    import socket # socket 一组接口
    # 买电话 实例化一个phone对象 socket.socket方法
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # socket.socket()方法 默认可以不写 默认就是基于TCP协议的socket  基于网络的是tcp  基于文件的是upd
    # socket.AF_INET,socket.SOCK_STREAM 是基于TCP协议的socket
    
    # 绑定电话卡 bind方法 绑定本地IP地址和端口
    phone.bind(('127.0.0.1',8848)) # 元组的形式
    # 127.0.0.1本地回环地址,只能自己连,别的都不能连
    
    # 开机监听 listen方法
    phone.listen(5)
    # 参数可以默认不写  写了之后允许连接有限制 多余的会进行等待
    # listen:允许5个人同时连接,先跟一个人聊,聊完了再跟另一个人聊 剩下的链接可以链接也可以等待
    
    # 等待连接
    print('等待连接')
    # 阻塞accept方法 等待连接 有人连接后再继续走
    # phone.accept()
    
    # 阻塞 等待客户端链接服务端,阻塞状态中 accent方法
    conn,addr = phone.accept()
    # conn 双向通信管理,连接作用
    # addr 客户端的ip地址和端口号
    
    # conn,addr返回一个元组,有两个参数
    print(conn) # 通信管理
    print(addr) # ip地址和端口号
    
    # from_client_data 来自客户端的问题
    # 接收到客户端的消息 recv方法 缓存区
    from_client_data = conn.recv(1024)
    # conn.recv(1024)  通道里面的缓冲区最多接收1024个字节
    # 1024 最多接收1024个字节
    
    # 输出接收到的客户端的消息
    print(f'来自客户端{addr[0]}的消息:{from_client_data.decode("utf-8")}')
    # addr[0] 取IP地址
    # from_client_data.decode将字节解码成utf-8
    
    # to_client_data 给客户端发消息
    to_client_data = input('服务器输入').strip().encode('utf-8')
    # strip() 把首位的空格切掉
    # encode('utf-8')将字节编码成字节型
    
    # send方法 服务端向客户端
    conn.send(to_client_data.upper())
    # upper()发送出的数据是大写的
    
    # 关闭双向通信连接
    conn.close()
    
    # 挂断电话 关闭连接
    phone.close()
    

    客户端

    # 导入socket模块
    import socket # 一组接口
    # 买电话 实例化一个phone对象
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 默认就是基于TCP协议的socket  AF_INET,socket.SOCK_STREAM基于网络的
    
    # 拨打电话 connect方法 连接服务器ip地址
    phone.connect(('127.0.0.1',8848))
    # 127.0.0.1 服务端的ip地址
    # 8848 端口是客户端随机分配的
    
    # to_server_data 给服务端的消息
    to_server_data = input('客户端输入')
    
    # send方法 发送消息
    phone.send(to_server_data.encode('utf-8'))
    # to_server_data.encode('utf-8') 给服务端的消息encode将字节编码成字节型
    
    # from_server_data 来自服务端的消息 recv缓存区
    from_server_data = phone.recv(1024)
    # recv(1024) 缓存区最多1024个字节
    
    # 打印
    print(f'来自服务器{from_server_data.decode("utf-8")}')
    # from_server_data.decode("utf-8") 来自服务端的消息decode将字节转码成utf-8
    
    # 关闭电话 关闭连接
    phone.close()
    

    纯代码

    服务端:
    import socket
    
    phone = socket.socket()
    
    phone.bind(('127.0.0.1',8848))
    
    phone.listen(2)
    
    conn,addr = phone.accept()
    print(conn)
    print(addr)
    
    from_client_data = conn.recv(1024)
    print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
    
    to_client_data = input('>>>').strip().encode('utf-8')
    conn.send(to_client_data)
    conn.close()
    phone.close()
    客户端:
    import socket
    
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    phone.connect(('127.0.0.1',8848))
    data = input('请输入>>>')
    
    phone.send(data.encode('utf-8'))
    from_server_data = phone.recv(1024)
    print(f'来自服务端的消息:{from_server_data}')
    
    phone.close()
    

    循环通信

    服务端

    # 一个聊完了继续往下接客户
    # 导入socket模块
    import socket # socket 一组接口
    # 买电话 实例化一个phone对象 socket.socket方法
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # socket.socket()方法 默认可以不写 默认就是基于TCP协议的socket  基于网络的是tcp  基于文件的是upd
    # socket.AF_INET,socket.SOCK_STREAM 是基于TCP协议的socket
    
    # 绑定电话卡 bind方法 绑定本地IP地址和端口
    phone.bind(('127.0.0.1',8848)) # 元组的形式
    # 127.0.0.1本地回环地址,只能自己连,别的都不能连
    
    # 开机监听 listen方法
    phone.listen(2)
    # 参数可以默认不写  写了之后允许连接有限制 多余的会进行等待
    # listen:允许2个人同时连接,先跟一个人聊,聊完了再跟另一个人聊 剩下的链接可以链接也可以等待
    # 实际有3个,有一个在于服务端建立链接
    
    print('等待连接')
    # while 循环接收链接
    
    
    # 阻塞 等待客户端链接服务端,阻塞状态中 accent方法
    conn,addr = phone.accept()
    # conn 双向通信管理,连接作用
    # addr 客户端的ip地址和端口号
    
    # 输出 conn通道信息和addrIP地址和端口
    print(f'链接来了:{conn,addr}')
    # while 循环输入连接
    while 1:# 1比True好用 循环收消息,循环发消息
        # try exception 异常处理
        # try 正常情况的代码
        try:
            # from_client_data 来自客户端的消息
            # 接收到客户端的消息 recv方法 缓存区
            from_client_data = conn.recv(1024)
            # conn.recv(1024)  通道里面的缓冲区最多接收1024个字节
            # 1024 最多接收1024个字节
    
            # if判断 来自客户端的信息是Q
            if from_client_data.upper() == b'Q':
            # upper() 给服务端的消息转化成大写
            # b'Q' 通过b方法将Q转成字节型
    
                # 输出正常退出
                print('客户端正常退出聊天了')
                # 终止循环
                break
            # 输出接收到的客户端的消息
            print(f'来自客户端{addr[0]}的消息:{from_client_data.decode("utf-8")}')
            # addr[0] 取IP地址
            # from_client_data.decode将字节解码成utf-8
    
            # to_client_data 给客户端发消息
            to_client_data = input('服务器输入').strip().encode('utf-8')
            # strip() 把首位的空格切掉
            # encode('utf-8')将字节编码成字节型
    
            # send方法 服务端向客户端
            conn.send(to_client_data.upper())
            # upper()发送出的数据是大写的
        # except 异常处理
        except ConnectionAbortedError:
        # ConnectionAbortedError 错误类型
    
            # 输出 客户端断了
            print('客户端链接中断了')
            # 终止while输入循环
            break
    
    # 退出循环链接 关闭双向通信连接
    conn.close()
    
    # 挂断电话 关闭连接
    phone.close()
    

    纯代码

    服务端:
    import socket
    
    phone = socket.socket()
    
    phone.bind(('127.0.0.1',8848))
    
    phone.listen(2)
    
    conn,addr = phone.accept()
    print(conn)
    print(addr)
    
    from_client_data = conn.recv(1024)
    print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
    
    to_client_data = input('>>>').strip().encode('utf-8')
    conn.send(to_client_data)
    conn.close()
    phone.close()
    客户端:
    import socket
    
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    phone.connect(('127.0.0.1',8848))
    data = input('请输入>>>')
    
    phone.send(data.encode('utf-8'))
    from_server_data = phone.recv(1024)
    print(f'来自服务端的消息:{from_server_data}')
    
    phone.close()
    

    循环链接通信

    服务端

    # 一个聊完了继续往下接客户
    # 导入socket模块
    import socket # socket 一组接口
    # 买电话 实例化一个phone对象 socket.socket方法
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # socket.socket()方法 默认可以不写 默认就是基于TCP协议的socket  基于网络的是tcp  基于文件的是upd
    # socket.AF_INET,socket.SOCK_STREAM 是基于TCP协议的socket
    
    # 绑定电话卡 bind方法 绑定本地IP地址和端口
    phone.bind(('127.0.0.1',8848)) # 元组的形式
    # 127.0.0.1本地回环地址,只能自己连,别的都不能连
    
    # 开机监听 listen方法
    phone.listen(2)
    # 参数可以默认不写  写了之后允许连接有限制 多余的会进行等待
    # listen:允许2个人同时连接,先跟一个人聊,聊完了再跟另一个人聊 剩下的链接可以链接也可以等待
    # 实际有3个,有一个在于服务端建立链接
    
    print('等待连接')
    # while 循环接收链接
    while 1: # while 1 比 while True的好处:效率高,不用在底层把True翻译成1
    # 开启循环链接模式,同时开3个,先连接第一个人,第一个结束后,去找下一个人
    # 3个人同时发送消息,先接受第一个人的,等第一个退出后,直接链接下一个人
    
        # 阻塞 等待客户端链接服务端,阻塞状态中 accent方法
        conn,addr = phone.accept()
        # conn 双向通信管理,连接作用
        # addr 客户端的ip地址和端口号
    
        # 输出 conn通道信息和addrIP地址和端口
        print(f'链接来了:{conn,addr}')
    # while 循环输入连接
        while 1:
            # try exception 异常处理
            # try 正常情况的代码
            try:
                # from_client_data 来自客户端的消息
                # 接收到客户端的消息 recv方法 缓存区
                from_client_data = conn.recv(1024)
                # conn.recv(1024)  通道里面的缓冲区最多接收1024个字节
                # 1024 最多接收1024个字节
    
                # if判断 来自客户端的信息是Q
                if from_client_data.upper() == b'Q':
                # upper() 给服务端的消息转化成大写
                # b'Q' 通过b方法将Q转成字节型
    
                    # 输出正常退出
                    print('客户端正常退出聊天了')
                    # 终止循环
                    break
                # 输出接收到的客户端的消息
                print(f'来自客户端{addr[0]}的消息:{from_client_data.decode("utf-8")}')
                # addr[0] 取IP地址
                # from_client_data.decode将字节解码成utf-8
    
                # to_client_data 给客户端发消息
                to_client_data = input('服务器输入').strip().encode('utf-8')
                # strip() 把首位的空格切掉
                # encode('utf-8')将字节编码成字节型
    
                # send方法 服务端向客户端
                conn.send(to_client_data.upper())
                # upper()发送出的数据是大写的
            # except 异常处理
            except ConnectionAbortedError:
            # ConnectionAbortedError 错误类型
    
                # 输出 客户端断了
                print('客户端链接中断了')
                # 终止while输入循环
                break
    
        # 退出循环链接 关闭双向通信连接
        conn.close()
    
    # 挂断电话 关闭连接
    phone.close()
    

    客户端

    # 客户端发一个q可以正常退出,且不能输入空
    # 导入socket模块
    import socket  # 一组接口
    
    # 买电话 实例化一个phone对象
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 默认就是基于TCP协议的socket  AF_INET,socket.SOCK_STREAM基于网络的
    
    # 拨打电话 connect方法 连接服务器ip地址
    phone.connect(('127.0.0.1', 8848))
    # 127.0.0.1 服务端的ip地址
    # 8848 端口是客户端随机分配的
    
    # 循环接收,发送消息
    while 1:
        # to_server_data 给服务端的消息
        to_server_data = input('客户端输入(输入q或者Q退出):').strip().encode('utf-8')
        # 发送空字符串服务端会阻塞 加个if判断,不能为空
        # 同时开多个,提示'输入'表示已经链接
    
        # if 判读 发给服务端的消息不为空
        if not to_server_data:
        # 服务端如果接受到了空的内容,服务端就会一直阻塞中,无论哪一方发送消息时,都不能为空
        # 必须一个recv 一个send
    
            # 输出提示
            print('输入的内容不能为空')
            # 继续判断是不是为空
            continue
        # send方法 发送消息
        phone.send(to_server_data)
    
        # if 判读发送给服务端的消息是不是q
        if to_server_data.upper() == b'Q':
        # upper() 给服务端的消息转化成大写
        # b'Q' 通过b方法将Q转成字节型
    
            # 是Q就终止循环
            break
    
    
        # from_server_data 来自服务端的消息 recv缓存区
        from_server_data = phone.recv(1024)
        # recv(1024) 缓存区最多1024个字节
    
        # 打印
        print(f'来自服务器{from_server_data.decode("utf-8")}')
        # from_server_data.decode("utf-8") 来自服务端的消息decode将字节转码成utf-8
    
    # 关闭电话 关闭连接
    phone.close()
    
    

    纯代码

    服务端:
    import socket
    
    phone = socket.socket()
    
    phone.bind(('127.0.0.1',8848))
    
    phone.listen(2)
    # listen: 2 允许有两个客户端加到半链接池,超过两个则会报错
    
    while 1:
        conn,addr = phone.accept()  # 等待客户端链接我,阻塞状态中
        print(f'链接来了: {conn,addr}')
    
        while 1:
            try:
                from_client_data = conn.recv(1024)  # 最多接受1024字节
    
                if from_client_data.upper() == b'Q':
                    print('客户端正常退出聊天了')
                    break
    
                print(f'来自客户端{addr}消息:{from_client_data.decode("utf-8")}')
                to_client_data = input('>>>').strip().encode('utf-8')
                conn.send(to_client_data)
            except ConnectionResetError:
                print('客户端链接中断了')
                break
        conn.close()
    phone.close()
    
    
    客户端:
    import socket
    
    phone = socket.socket()
    
    phone.connect(('127.0.0.1',8848))
    while 1:
        to_server_data = input('>>>输入q或者Q退出').strip().encode('utf-8')
        if not to_server_data:
            # 服务端如果接受到了空的内容,服务端就会一直阻塞中,所以无论哪一端发送内容时,都不能为空发送
            print('发送内容不能为空')
            continue
        phone.send(to_server_data)
        if to_server_data.upper() == b'Q':
            break
        from_server_data = phone.recv(1024)  # 最多接受1024字节
        print(f'来自服务端消息:{from_server_data.decode("utf-8")}')
    
    phone.close()
    

    执行远程命令

    服务端

    # 输入命令,错误的提示非命令,正确的打印出执行的命令
    # help是正确的命令
    # 命令后最好不要加空格
    
    # 导入socket模块
    import socket # socket 一组接口
    # 导入subprocess模块
    import subprocess # subprocess 远程命令
    # 买电话 实例化一个phone对象 socket.socket方法
    phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # socket.socket()方法 默认可以不写 默认就是基于TCP协议的socket  基于网络的是tcp  基于文件的是upd
    # socket.AF_INET,socket.SOCK_STREAM 是基于TCP协议的socket
    
    # 绑定电话卡 bind方法 绑定本地IP地址和端口
    phone.bind(('127.0.0.1',8847)) # 元组的形式
    # 127.0.0.1本地回环地址,只能自己连,别的都不能连
    
    # 开机监听 listen方法
    phone.listen(2)
    # 参数可以默认不写  写了之后允许连接有限制 多余的会进行等待
    # listen:允许2个人同时连接,先跟一个人聊,聊完了再跟另一个人聊 剩下的链接可以链接也可以等待
    # 实际有3个,有一个在于服务端建立链接
    
    
    print('等待连接')
    # while 循环接收链接
    while 1:
    # 开启循环链接模式,同时开3个,先连接第一个人,第一个结束后,去找下一个人
    # 3个人同时发送消息,先接受第一个人的,等第一个退出后,直接链接下一个人
    
    
        # 阻塞 等待客户端链接服务端,阻塞状态中 accent方法
        conn,addr = phone.accept()
        # conn 双向通信管理,连接作用
        # addr 客户端的ip地址和端口号
    
        # 输出 conn通道信息和addrIP地址和端口
        print(f'链接来了:{conn,addr}')
    # while 循环输入连接
        while 1:
            # try exception 异常处理
            # try 正常情况的代码
            try:
                # from_client_data 来自客户端的消息
                # 接收到客户端的消息 recv方法 缓存区
                from_client_data = conn.recv(1024)
                # conn.recv(1024)  通道里面的缓冲区最多接收1024个字节
                # 1024 最多接收1024个字节
    
                # if判断 来自客户端的信息是Q
                if from_client_data.upper() == b'Q':
                # upper() 给服务端的消息转化成大写
                # b'Q' 通过b方法将Q转成字节型
    
                    # 输出正常退出
                    print('客户端正常退出聊天了')
                    # 终止循环
                    break
    
                obj = subprocess.Popen(from_client_data.decode('utf-8'),
    
                                       shell = True, # shell 命令解释器,相当于调用cmd 执行指定的命令
                                       stdout = subprocess.PIPE, # 正确的命令 丢到管道中
                                       stderr = subprocess.PIPE, # 错误的命令 丢到另一个管道中
                                       )
                # obj = subprocess.Popen() obj对象 = subprocess模块.Popen方法
                # from_client_data 来自客户端的信息
                # decode('utf-8') 解码成utf-8类型
                # windows操作系统默认编码是gbk编码
    
                print(obj) # <subprocess.Popen object at 0x1030de2e8> 得到对象的地址
                # result 同时输入正确的方法和错误的方法
                result = obj.stdout.read() + obj.stderr.read()
                # obj.stdout.read() 正确的管道
                # obj.stderr.read() 错误的管道
                print(result) # 得到所有管道的信息
    
                # send方法 服务端向客户端
                conn.send(result)
            # except 异常处理
            except ConnectionAbortedError:
            # ConnectionAbortedError 错误类型
    
                # 输出 客户端断了
                print('客户端链接中断了')
                # 终止while输入循环
                break
    
        # 退出链接循环 关闭双向通信连接
        conn.close()
    
    # 挂断电话 关闭连接
    phone.close()
    
    

    客户端

    # 客户端发一个q可以正常退出,且不能输入空
    # 导入socket模块
    import socket  # 一组接口
    
    # 买电话 实例化一个phone对象
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 默认就是基于TCP协议的socket  AF_INET,socket.SOCK_STREAM基于网络的
    
    # 拨打电话 connect方法 连接服务器ip地址
    phone.connect(('127.0.0.1', 8847))
    # 127.0.0.1 服务端的ip地址
    # 8848 端口是客户端随机分配的
    
    # 循环接收,发送消息
    while 1:
        # to_server_data 给服务端的消息
        to_server_data = input('客户端输入(输入q或者Q退出):').strip().encode('utf-8')
        # 发送空字符串服务端会阻塞 加个if判断,不能为空
        # 同时开多个,提示'输入'表示已经链接
    
        # if 判读 发给服务端的消息不为空
        if not to_server_data:
        # 服务端如果接受到了空的内容,服务端就会一直阻塞中,无论哪一方发送消息时,都不能为空
        # 必须一个recv 一个send
    
            # 输出提示
            print('输入的内容不能为空')
            # 继续判断是不是为空
            continue
        # send方法 发送消息
        phone.send(to_server_data)
    
        # if 判读发送给服务端的消息是不是q
        if to_server_data.upper() == b'Q':
        # upper() 给服务端的消息转化成大写
        # b'Q' 通过b方法将Q转成字节型
    
            # 是Q就终止循环
            break
    
    
        # from_server_data 来自服务端的消息 recv缓存区
        from_server_data = phone.recv(1024)
        # recv(1024) 缓存区最多1024个字节
    
        # 打印
        print(f'来自服务器{from_server_data.decode("utf-8")}')
        # from_server_data.decode("utf-8") 来自服务端的消息decode将字节转码成utf-8
    
    # 关闭电话 关闭连接
    phone.close()
    
    

    纯代码

    服务端:
    import socket
    import subprocess
    
    phone = socket.socket()
    phone.bind(('127.0.0.1',8867))
    
    phone.listen(3)
    
    while 1:
        conn,addr = phone.accept()
        print(f'链接来自:{conn,addr}')
        while 1:
            try:
                from_client_data = conn.recv(1024)
    
                obj = subprocess.Popen(from_client_data.decode("utf8"),
                                       shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE,
                                       )
                result = obj.stdout.read() + obj.stderr.read()
    
                conn.send(result)
            except ConnectionError:
                print('客户端链接中断了')
                break
    
        conn.close()
    phone.close()
    客户端:
    
    import socket
    import subprocess
    
    phone = socket.socket()
    phone.connect(('127.0.0.1', 8867))
    
    while 1:
    
        to_server_data = input('>>>请输入cmd命令,输入Q或q退出').strip().encode('utf8')
    
        if not to_server_data:
            print('发送内容不能为空!')
            continue
    
        phone.send(to_server_data)
        if to_server_data.upper() == b'Q':
            break
    
        from_server_data = phone.recv(1024)
        print(f'来自服务端的消息:{from_server_data.decode("utf8")}')
    
    phone.close()
    
    
  • 相关阅读:
    daper
    存储过程事务
    dengluzhucehaiyouxianshiMVC
    遍历加监听
    类的操作
    轮播图
    定时器的应用(三)
    定时器的应用(二)
    定时器的应用(一)
    延时调用
  • 原文地址:https://www.cnblogs.com/zhangshan33/p/11354797.html
Copyright © 2011-2022 走看看