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()
相关文章
相关标签/搜索