Python-Socket

一、参考

1. python之socket编程

2. socket编程 (byhy.net)

二、相关概念

我们作为程序员,只要知道,我们的程序如何把 所要发送的信息 交给 快递公司取件人 , 如何从 快递公司送件人 手中获取信息。

那么 和我们的 应用程序 直接打交道的 快递公司取件人快递公司送件人 到底是什么? 就是操作系统 提供的 socket 编程接口

发送信息的应用程序,通过 socket 编程接口 把信息给操作系统的TCP/IP协议栈通讯模块;

通讯模块一层层传递给 其他通讯模块(网卡驱动等),最后再通过网卡等硬件设备发送到网络上去;

经过 网络上路由器的一次次转发,最终到了 目的程序 所在的 计算机(或者手机等设备) , 再通过 其 操作系统的 TCP/IP协议栈通讯模块 一层层上传。

最后接收信息的程序,通过 socket 编程接口 接收到了 传输的信息。

这个过程可以用下图来表示

我们前面使用过 requests库 发送 HTTP请求消息,其实 requests库底层也是使用的socket编程接口发送HTTP请求消息。

HTTP 传输的消息 底层也是通过 TCP/IP 协议 传输的, HTTP 加上了一些额外的规定, 比如传输消息的格式。

就像我们发快递的时候做了些额外的处理。比如 把物品 放到一个盒子里。

三、快速入门

3.1 客户端

ini 复制代码
#  === TCP 客户端程序 client.py ===

from socket import *

IP = '127.0.0.1'
SERVER_PORT = 50000
BUFLEN = 1024

# 实例化一个socket对象,指明协议
dataSocket = socket(AF_INET, SOCK_STREAM)

# 连接服务端socket
dataSocket.connect((IP, SERVER_PORT))

while True:
    # 从终端读入用户输入的字符串
    toSend = input('>>> ')
    if  toSend =='exit':
        break
    # 发送消息,也要编码为 bytes
    dataSocket.send(toSend.encode())

    # 等待接收服务端的消息
    recved = dataSocket.recv(BUFLEN)
    # 如果返回空bytes,表示对方关闭了连接
    if not recved:
        break
    # 打印读取的信息
    print(recved.decode())

dataSocket.close()

3.2 服务端

python 复制代码
#  === TCP 服务端程序 server.py ===

# 导入socket 库
from socket import *

# 主机地址为空字符串,表示绑定本机所有网络接口ip地址
# 等待客户端来连接
IP = '127.0.0.1'
# 端口号
PORT = 50000
# 定义一次从socket缓冲区最多读入512个字节数据
BUFLEN = 512

# 实例化一个socket对象
# 参数 AF_INET 表示该socket网络层使用IP协议
# 参数 SOCK_STREAM 表示该socket传输层使用TCP协议
listenSocket = socket(AF_INET, SOCK_STREAM)

# socket绑定地址和端口
listenSocket.bind((IP, PORT))


# 使socket处于监听状态,等待客户端的连接请求
# 参数 8 表示 最多接受多少个等待连接的客户端
listenSocket.listen(8)
print(f'服务端启动成功,在{PORT}端口等待客户端连接...')

dataSocket, addr = listenSocket.accept()
print('接受一个客户端连接:', addr)

while True:
    # 尝试读取对方发送的消息
    # BUFLEN 指定从接收缓冲里最多读取多少字节
    recved = dataSocket.recv(BUFLEN)

    # 如果返回空bytes,表示对方关闭了连接
    # 退出循环,结束消息收发
    if not recved:
        break

    # 读取的字节数据是bytes类型,需要解码为字符串
    info = recved.decode()
    print(f'收到对方信息: {info}')

    # 发送的数据类型必须是bytes,所以要编码
    dataSocket.send(f'服务端接收到了信息 {info}'.encode())

# 服务端也调用close()关闭socket
dataSocket.close()
listenSocket.close()

3.3 效果演示

当客户端发送数据给服务端后,服务端会反馈给客户端接收到的消息

注意:

开启socket服务后,会开启三个socket服务

第一行socket服务表示服务端等待客户端的连接,状态为LISTENING

服务端一旦连接成功后,会建立两个socket(对应第二行和第三行),状态均为ESTABLISHED

他俩自己的端口号和发送给其他的端号互为相反

复制代码
PS Z:\python> netstat -ano|findstr 60000
  TCP    127.0.0.1:60000        0.0.0.0:0              LISTENING       18064
  TCP    127.0.0.1:50764        127.0.0.1:60000        ESTABLISHED     23812
  TCP    127.0.0.1:60000        127.0.0.1:50764        ESTABLISHED     18064

四、应用消息格式

对于使用TCP协议传输信息的程序来说,格式定义一定要明确规定 消息的边界

因为 TCP协议传输的是 字节流(bytes stream), 如果消息中没有指定 边界 或者 长度,接收方就不知道一个完整的消息从字节流的 哪里开始,到 哪里结束。

指定消息的边界有两种方式:

  • 用特殊字节作为消息的结尾符号

    可以用消息内容中不可能出现的字节串 (比如 FFFFFF) 作为消息的结尾字符。

  • 在消息开头某个位置,直接指定消息的长度

    比如在一个消息的最前面用2个字节表示本消息的长度。

UDP协议通常不需要指定消息边界,因为UDP是数据报协议,应用程序从socket接收到的必定是发送方发送的完整消息。

相关推荐
颜酱18 分钟前
# 02 | 搭骨架:用 LangGraph 编排 12 步工作流(思路)
前端·人工智能·后端
颜酱19 分钟前
02 | 搭骨架:用 LangGraph 编排 12 步工作流
前端·人工智能·后端
嘉伟桑1 小时前
Python调用电价API返回JSON示例:分时电价、现货电价和字段解析
后端
武子康2 小时前
Shippy:确定性工具、会话级 Sandbox 与 Live-Data Eval(4 类收敛 + 7 步实现方案 + 6 类评测指标)
前端·人工智能·后端
我叫黑大帅2 小时前
我为什么单一消费者的场景下,要用 Redis List 当消息队列?
redis·后端·面试
AskHarries2 小时前
文件上传系统
后端
止语Lab3 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活3 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
程序员天天困3 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn3 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端