Socket 传情:用 Python 编织 TCP 网络

news2024/9/21 0:31:40

文章目录

  • 参考
  • 描述
  • TCP 服务器端与 TCP 客户端通信的基本流程
      • 服务器端
      • 客户端
  • 使用 socket 实现 TCP 服务器端
      • 实现监听套接字
        • socket.socket()
        • Socket().bind()
          • IP 地址的选择
            • 本地回环地址
            • 某一特定 IP 地址
            • 空字符串
        • Socket().listen()
        • 监听套接字的实现
      • 实现连接套接字
        • Socket().accept()
        • conn.send()
        • 监听套接字的实现
      • 数据收发
        • conn.recv()
        • 具体实现
      • 关闭套接字
      • 代码总汇
  • 使用 socket 实现 TCP 客户端
        • Socket().connect()
        • 具体实现
  • TCP 服务器与 TCP 客户端的双向通信

参考

项目描述
Python 官方文档https://docs.python.org/zh-cn/3/
搜索引擎Google 、Bing

描述

项目描述
操作系统Windows 10 专业版
PyCharm2023.1 (Professional Edition)
Python3.10.6

TCP 服务器端与 TCP 客户端通信的基本流程

服务器端

  1. 创建一个监听套接字对象,指定地址族(IPV4IPV6)和套接字类型(TCP 套接字UDP 套接字)。

  2. 通过使用 bind() 方法为监听套接字指定套接字地址。

  3. 调用 listen() 方法以指示监听套接字 开始 对客户端的连接请求进行监听。

  4. 通过调用 accept() 方法接受客户端的连接请求,该方法将返回一个连接套接字及客户端套接字的套接字地址。

  5. 通过连接套接字与客户端进行通信,使用 recv() 方法接收客户端发送的数据,使用 send() 方法向客户端发送响应。

  6. 重复步骤 5,直到通信完成。

  7. 关闭服务器套接字。

客户端

  1. 创建一个客户端套接字对象,并为该套接字指定 地址族套接字类型

  2. 调用 connect() 方法通过服务器的监听套接字向服务器端发起连接请求。

  3. 通过客户端套接字与服务器进行通信,使用 send() 向服务器发送数据,使用 recv()方法接收服务器端返回的响应。

  4. 重复步骤 3,直到通信完成。

  5. 关闭客户端套接字。

使用 socket 实现 TCP 服务器端

实现监听套接字

socket.socket()

socket 模块中,socket() 类用于创建 套接字对象

class socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, fileno=None)

其中:

参数描述
family指定地址族类型,默认为 IPV4socket 模块提供常量 socket.AF_INETsocket.AF_INET6 分别用于指定地址族 IPV4IPV6
type指定套接字类型,默认为 TCP 套接字socket 模块提供常量 socket.SOCK_STREAMsocket.SOCK_DGRAM 分别用于指定 TCP 套接字与 UDP 套接字。
proto指定套接字所使用的传输层协议,默认值为 0。使用 默认值 0 意味着 socket() 将依据参数 familytype 的值自动选择合适的传输层协议。socket 模块提供了常量 socket.IPPROTO_TCPsocket.IPPROTO_UDP 分别用于指定传输层协议 TCPUDP
fileno指定套接字所使用的 文件描述符(文件描述符是操作系统中用于标识打开文件或套接字的整数值),使用同一文件描述符的 套接字对象将 被视为同一个 套接字

Socket().bind()

socket 对象的 bind() 函数用于为 监听套接字 指定 套接字地址。在 socket 编程中,套接字地址通常使用 元组 进行存储。其中,元组的第一个元素为 IP 地址,元组中的第二个元素为 端口号

IP 地址的选择

假设我们有一台服务器,具有两个网络接口 eth0eth1,分别对应 IP 地址 192.168.1.1010.0.0.5

本地回环地址

如果我们使用 127.0.0.1localhost 作为监听套接字的 IP 地址,那么监听套接字将只监听来自 本地回环接口(Loopback Interface) 的连接请求,这意味着只有本机上的进程可以通过 localhost127.0.0.1 与服务器建立连接,而来自其他网络接口的连接请求将被忽略。
本地回环接口是一个特殊的网络接口,通常用于本机内部的通信。本地回环接口的 IP 地址 通常设置为127.0.0.1,该 IP 地址通常被称为 本地主机地址
当监听套接字的监听地址被设置为 127.0.0.1 时,该套接字将仅监听来自本地回环接口的连接请求,而不会监听来自其他网络接口的连接。

注:

通过本地回环地址 127.0.0.1localhost 访问主机时,数据不需要经过物理网络接口进行传输。

某一特定 IP 地址

如果我们使用某一特定的 IP 地址,如 192.168.1.10 作为监听套接字的 IP 地址,那么监听套接字将仅监听来自 192.168.1.10 的连接请求。对于 10.0.0.5 的连接请求不予理会。

空字符串

当将一个 空字符串 作为套接字地址中的 IP 地址传递给 bind() 函数时,该函数会将监听套接字绑定到 系统上所有可用的网络接口,这意味着监听套接字将监听所有来自可用的网络接口上的连接请求。

如果我们使用 空字符串 作为监听套接字地址的 IP 地址,那么监听套接字将监听来自网络接口 eth0eth1本地回环接口 的连接请求。

Socket().listen()

socket 对象的 listen() 方法的作用是告诉操作系统该套接字应该 开始监听传入的连接请求。一旦调用了 listen() 方法,该套接字就将进入监听状态,并开始等待客户端的连接请求。

Socket().listen(backlog=5)

listen() 方法接收一个参数 backlog,用于指定操作系统在未接受连接之前可以排队等待的 最大连接数
如果等待被处理的连接请求的数量即将超过最大连接数,则后续的客户端连接请求 可能 将被 拒绝。参数 backlog 的取值为一个 大于或等于零的整数,若参数值小于零,则该参数的 实际值 将为零。

监听套接字的实现

import socket as sk


# 规定监听套接字地址
HOST = ''
PORT = 8080

# 创建监听套接字
monitor = sk.socket()
# 为监听套接字指定套接字地址
monitor.bind((HOST, PORT))
# 启用监听套接字以监听来自客户端的连接请求
monitor.listen(100)

# 向控制台中输出服务器当前的运行状态
print(f'The Server is running at {"localhost" if HOST == "" else HOST}: {PORT}')

实现连接套接字

Socket().accept()

socketaccept() 方法的作用是在套接字进入监听模式后,阻塞当前线程并等待客户端的连接请求。一旦有客户端连接请求到达,accept() 方法将返回一个 连接套接字对象客户端套接字的地址。通过连接套接字对象,服务器端将能够与客户端进行通信。

conn.send()

连接套接字对象的 send() 方法 的作用是将数据发送到 已连接的套接字,以便将数据传输到远程主机。send() 方法将返回已发送数据的 字节数,若因为某些不可控因素导致数据 仅部分 发送至目标套接字,则程序需要自行处理数据未完全发送的情况。

连接套接字对象还具有一个与 send() 方法类似的方法 sendall()sendall() 方法的作用是将指定的数据发送到已连接的套接字。与 send() 方法不同的是,sendall() 方法会自动处理数据仅部分发送的情况,并保证所有数据都被发送出去。若数据无法 全部 发送至目标套接字,则该方法将 抛出异常

注:

使用 send()sendall() 方法仅能够向远程主机传递二进制数据。通过调用字符串对象的 encode() 方法将能够得到该字符串对象的二进制数据形式。

监听套接字的实现

# 创建连接套接字
conn, addr = monitor.accept()

# 在接收到来自客户端的连接请求后
# 向控制台中输出相关提示信息。
print(f'The Server has received a connection from {addr[0]}: {addr[1]}')

# 向客户端发送成功连接至服务器的提示信息
# 在发送数据前需要通过 encode() 方法对发送数据进行 UTF-8 编码操作,
# 以将字符串类型数据转换为二进制数据。
conn.send('Can I help you?'.encode())

数据收发

conn.recv()

连接套接字对象的 recv() 方法,能够接收来自 客户端套接字 的数据,并将接收到的数据存储在指定大小的 缓冲区 中。

recv() 方法允许传递一个参数,用以指定存储数据的缓冲区大小(以字节为单位)。如果接收到的数据大小超过了设定缓冲区大小,那么服务器端将仅能够接收到缓冲区大小的数据。因此在实际使用时,通常需要在一个循环中多次调用recv()方法,直到接收到所需的所有数据。

注:

recv() 方法是一个 阻塞调用,即在没有接收到数据时,当前线程将会被阻塞,直到接收到数据或发生错误。可以通过调用 socket.setdefaulttimeout() 函数设置套接字的超时时长以控制阻塞的行为,当阻塞时长大于设定的超时时长时,recv() 方法将抛出异常。

具体实现

message = 'Content From Client'
while True:
    # 接收信息并将其输出至控制台中。
    # 由于接收到的数据为二进制数据,故在使用接收到的数据前
    # 需要使用 decode() 方法对其进行解码操作。
    message = conn.recv(9999).decode()
    print(f'【Client】 {message}')

    # 在客户端发送 Bye(不考虑大小写)后进行响应并终止循环
    if message.lower() == 'bye':
        conn.send('Bye'.encode())
        break

    # 通过控制台指定发送数据并通过 send() 函数将其发送至客户端
    think = input('>>> ')
    conn.send(think.encode())

关闭套接字

可以通过调用套接字对象的 close() 方法来关闭套接字及其现有的连接。
在套接字无需使用时,关闭套接字有助于防止资源泄露和保持系统的稳定性。如果不及时关闭套接字,可能会导致资源的浪费和应用程序的异常行为。此外,关闭套接字还可以 确保连接的清理和释放,以便其他应用程序能够使用 相同的端口 进行通信。

# 关闭连接套接字
conn.close()

# 关闭监听套接字
monitor.close()

代码总汇

import socket as sk


# 规定监听套接字地址
HOST = ''
PORT = 8080

# 创建监听套接字
monitor = sk.socket()
# 为监听套接字指定套接字地址
monitor.bind((HOST, PORT))
# 启用监听套接字以监听来自客户端的连接请求
monitor.listen(100)

# 向控制台中输出服务器当前的运行状态
print(f'The Server is running at {"localhost" if HOST == "" else HOST}: {PORT}')

# 创建连接套接字
conn, addr = monitor.accept()

# 在接收到来自客户端的连接请求后
# 向控制台中输出相关提示信息。
print(f'The Server has received a connection from {addr[0]}: {addr[1]}')

# 向客户端发送成功连接至服务器的提示信息
# 在发送数据前需要通过 encode() 方法对发送数据进行 UTF-8 编码操作,
# 以将字符串类型数据转换为二进制数据。
conn.send('Can I help you?'.encode())

message = 'Content From Client'
while True:
    # 接收信息并将其输出至控制台中。
    # 由于接收到的数据为二进制数据,故在使用接收到的数据前
    # 需要使用 decode() 方法对其进行解码操作。
    message = conn.recv(9999).decode()
    print(f'【Client】 {message}')

    # 在客户端发送 Bye(不考虑大小写)后进行响应并终止循环
    if message.lower() == 'bye':
        conn.send('Bye'.encode())
        break

    # 通过控制台指定发送数据并通过 send() 函数将其发送至客户端
    think = input('>>> ')
    conn.send(think.encode())

# 关闭连接套接字
conn.close()

# 关闭监听套接字
monitor.close()

使用 socket 实现 TCP 客户端

Socket().connect()

socket 对象的 connect() 方法用于在客户端中通过 客户端套接字 向服务器端的 监听套接字 发起连接请求。

connect() 方法接收一个二元元组作为实参,该元组用于表示服务器端监听套接字的套接字地址。
connect() 方法没有返回值,它会尝试与指定的服务器建立连接。若连接建立失败,该方法将会抛出异常

具体实现

import socket as sk


# 指定服务器端的监听套接字的套接字地址
HOST = '127.0.0.1'
PORT = 8080

# 创建客户端套接字
client = sk.socket()
# 通过 connect() 方法指定服务器端
# 监听套接字的套接字地址以向服务器端发起连接请求
client.connect((HOST, PORT))

message = 'Content From Server'
while True:
    # 接收信息并将其输出至控制台中。
    # 由于接收到的数据为二进制数据,故在使用接收到的数据前
    # 需要使用 decode() 方法对其进行解码操作。
    message = client.recv(9999).decode()
    print(f'【Server】 {message}')

    # 在服务器端发送 Bye(不考虑大小写)后进行响应并终止循环
    if message.lower() == 'bye':
        # 在发送数据前需要通过 encode() 方法对发送数据进行 UTF-8 编码操作,
        # 以将字符串类型数据转换为二进制数据。
        client.send('Bye'.encode())
        break

    # 通过控制台指定发送数据并通过 send() 函数将其发送至服务器端
    think = input('>>> ')
    client.send(think.encode())

# 关闭客户端套接字
client.close()

TCP 服务器与 TCP 客户端的双向通信

在进行 socket 编程 时,需要注意服务器端与客户端的 运行顺序TCP 服务器端 程序需要先于 TCP 客户端 程序运行。确保服务器先启动并能够对来自客户端的连接请求进行监听,然后客户端再启动并尝试连接到服务器端,这样可以确保服务器能够接受客户端的连接请求并建立有效的通信通道。

在运行上述 TCP 服务器端与 TCP 客户端实现后,存在如下运行效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/638777.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【I2C】Linux使用GPIO模拟I2C

文章目录 1. I2C GPIO系统架构简介2. 如何使能I2C GPIO驱动2.1 config配置2.2 dts配置2.3 测试验证 3. 简单分析i2c-gpio.c驱动3.1 解析设备树3.2 配置SDA和SCL3.3 注册到i2c-algo-bit.c 4. 简单分析i2c-algo-bit.c驱动4.1 提供I2C通信时的算法4.2 注册Adapter 5. 参考资料 1. …

翻车了,被读者找出 BUG

大家好呀,我是小楼。 本文是上篇文章《使用增强版 singleflight 合并事件推送,效果炸裂!》的续集,没看过前文必须要先看完才能看本文,实在不想看,拉到文章末尾,给我点个赞再退出吧~Doge 上篇文…

如何进行App性能测试?SoloPi是最佳选择!

目录 引言 SoloPi简介 SoloPi特点 SoloPi的主要功能 下载SoloPi 安装SoloPi 使用SoloPi进行性能测试 性能数据查看与记录 环境加压 响应耗时计算工具 注意事项 Solopi提供的各项性能指标介绍 引言 大家好!我是凡哥。 今天我想跟你们分享一下如何进行A…

Python的接口自动化-读写excel文件

目录 引言 一、xlrd、xlwt以及xlutils安装 二、xlrd操作excel文件的数据读取 三、xlwt向excel文件写入数据 四、xlutils操作excel文件 五、封装操作excel读和写的类 引言 使用python进行接口测试时常常需要接口用例测试数据、断言接口功能、验证接口响应状态等&#xff0…

Mysql升级8.0后日期类型兼容性问题

背景 最近对原有项目数据库进行升级,从MySQL 5.7 升级到8.0,因此项目种的驱动程序也要做相应升级。 问题 一、 升级后报:java.time.LocalDateTime cannot be cast to java.util.Date 该问题是因为代码中使用Map类型获取查询返回值&#xf…

lightdb检测不兼容工具CheckUnsupportOracle使用说明

oracle有很多特性在lightdb无法使用,使用该工具可以即时扫描某个在线数据库或本地文件夹中有哪些不兼容特性,-a -x对oracle不兼容特性有所区别,扫描范围可参考后续表格。 0、使用限制 默认扫描存储过程,函数及包默认仅支持oracl…

19JS10——预解析

文章目录 一、预解析二、变量预解析和函数预解析三、预解析案例1、案例1:结果是几?2、案例2:结果是几?3、案例3:结果是几?4、案例4:结果是几? 目标: 1、预解析 2、变量预…

电脑连上wifi但显示无网解决方案分享,轻松搞定电脑上网问题

有的时候我们会遇到这样的问题:电脑明明连接了网络但仍不能上网,并且出现错误提示“WiFi已连接但没有互联网”。遇到这种情况,我们可以先使用另一台设备访问网络,看看你能否正常上网。如果也不能上网,可以尝试重新启动…

七牛云存储开启referer防盗链后,微信小程序访问提示403

点击七牛云存储存储桶绑定的加速域名 配置站点域名和微信小程序域名 是否允许空Referer一定要打开,否则小程序上的视频或图片访问时将提示403

# 如何在Git上更改本地分支名称和远程分支名称

有时候我们需要修改git分支名称,例如不合理的分支名称。本篇文章分享了如何轻松地修改Git本地分支名称和修改远程分支名称。 在Git中,通常使用分支来使开发与您的主要工作流程分开。在软件工程团队中,通常要实施特定的工作流程。例如&#x…

[C语言实现]数据结构之《关于我转生成队列这档事》

🥰作者: FlashRider 🌏专栏: 数据结构 🍖知识概要:详解队列的概念、顺序队列和链式队列的优点和缺点,以及代码实现。 目录 什么是队列? 选择什么结构来实现队列? 链式队列的实现 队列的结构…

在UE中使用Stencil功能

Stencil是指利用深度buffer的后8位数据进行bit mask信息的绘制,从而制作类似角色mask遮罩等效果,下面就在UE中进行制作。 1.首先在Project Settings项目设置中开启stencil,搜索stencil关键字在Custom Depth Stencil Pass选项中设置为Enabled…

PNAS:勘探地球物理学论文

阅读 《Sensing prior constraints in deep neural networks for solving exploration geophysical problems dendrimers》 题目译为《深度神经网络中用于解决勘探地球物理问题的感知先验约束》 研究意义 该研究提出三种可能的策略,以有效地讲地质和/或地球物理约…

面试官再问分布式事务,三天吃透这份至尊级学习笔记怼他

分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式…

ABAP 新语法--Open SQL(草稿)

1. 常量 1.1 常量赋值 常量字段可以用来为内表中的部分字段赋初始值,字段类型和长度依据输入常量的值决定 SELECTmara~matnr, " 物料号mara~matkl, " 物料组mara~mtart, " 物料类型 AS lkenz, " 删除标识,常量空字符串123 AS fla…

QCon高分演讲:火山引擎容器技术在边缘计算场景下的应用实践与探索

近日,火山引擎边缘云原生团队的同学在QCon全球软件开发大会上分享了火山引擎容器技术在边缘计算场景下的应用实践与探索,并在一众AIGC、LLM等当下热门议题中脱颖而出,入选观众满意度投票中“叫好又叫座议题Top5”。 以下是演讲全文&#xff1…

论文阅读 Interpretable Unified Language Checking

本文提出了一种新的方法来解决多种自然语言处理任务中的问题,包括公平性检查、事实检查、虚假新闻检测和对抗攻击检测等。该方法基于大型语言模型和少量人类标注的提示信息,通过在模型中引入相应的提示,来提高模型的性能和可解释性。该论文的…

数据库索引及优化

索引 1.索引简介 1.1 概念 MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。索引的本质:索引是数据结构。 注:在数据之外,数据库系统还维护着满足特定查找算法的数据结构&…

第二章---感知机

🌞欢迎来到深度学习的世界 🌈博客主页:卿云阁 💌欢迎关注🎉点赞👍收藏⭐️留言📝 🌟本文由卿云阁原创! 🙏作者水平很有限,如果发现错误&#xff…

centos各个版本jenkins部署

目录 官网安装方法 安装java,**注意java版本,新版本jenkins只支持jdk11及以上 安装jenkins Jenkins启动失败的七个问题 jenkins 部署脚本 Nginx转发jenkins服务 官网安装方法 Redhat Jenkins Packages (jenkins-ci.org)https://mirrors.jenkins-c…