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接收到的必定是发送方发送的完整消息。

相关推荐
Yaml41 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
小码编匠2 小时前
一款 C# 编写的神经网络计算图框架
后端·神经网络·c#
AskHarries2 小时前
Java字节码增强库ByteBuddy
java·后端
佳佳_2 小时前
Spring Boot 应用启动时打印配置类信息
spring boot·后端
许野平3 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
BiteCode_咬一口代码4 小时前
信息泄露!默认密码的危害,记一次网络安全研究
后端
齐 飞5 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
LunarCod5 小时前
WorkFlow源码剖析——Communicator之TCPServer(中)
后端·workflow·c/c++·网络框架·源码剖析·高性能高并发
码农派大星。6 小时前
Spring Boot 配置文件
java·spring boot·后端