Chapter 40 Socket网络编程

欢迎大家订阅【Python从入门到精通】专栏,一起探索Python的无限可能!


前言

在现代计算机网络中,Socket(套接字)是实现进程之间通信的重要工具。在网络应用中,Socket 充当了进程间数据传输的搬运工,负责进程之间的网络数据传输。无论是服务器还是客户端,二者通过 Socket 进行通信,形成了网络应用的基础。本章详细讲解了Socket服务端开发以及Socket客户端开发。


本篇文章参考:黑马程序员

一、Socket网络编程

Socket 是网络编程中用于建立和管理网络连接的一种抽象,主要用于服务端和客户端之间的通信。
①Socket服务端

  • 监听请求: 服务端负责等待并监听来自客户端的连接请求。
  • 接受连接: 每当有客户端连接时,服务端使用 accept() 方法接受该连接,并为该特定连接创建一个新的 Socket 对象。这个连接对象用于与连接的特定客户端进行通信。
  • 处理多个客户端: 服务端可以同时处理多个客户端的请求,每个连接都由一个独立的 conn 对象管理。

②Socket客户端

  • 发起连接: 客户端的作用是发起与服务端的连接请求。它通常只有一个主要的 Socket 对象,用于与服务端进行通信。
  • 一次一连接: 一般来说,客户端一次只会与一个服务端建立连接。

在这里插入图片描述

二、Socket服务端编程

①导包并创建socket对象
import socket
socket_server=socket.socket()

②绑定socket_server到指定IP和地址
socket_server.bind((host, port))

  • bind()方法:是 socket 对象的方法,用于将一个地址(主机名和端口号)绑定到一个 Socket 上,通常用于服务器端。
  • 参数(host, port): 一个元组,其中 host 通常是 IP 地址,port 是整数形式的端口号。

【示例】

# 绑定socket_server到指定IP和地址
socket_server.bind(("localhost",8888))
  • localhost:一个特殊的主机名,表示本地计算机。它允许服务端在本机上进行测试而不需要连接外部网络。
  • 8888:要绑定的端口号。端口号用于标识特定的服务或进程。在这个例子中,服务端将在本地的 8888 端口上监听来自客户端的连接请求。

③服务端开始监听端口
socket_server.listen(backlog)

  • listen方法:用于将 Socket 设置为被动模式,以便接收来自客户端的连接请求。
  • 参数backlog:为 int 整数,表示允许的连接请求数量。如果同时有多个客户端请求连接,超出该数量的请求将被拒绝。该参数是可选的,如果不指定,系统会自动设置一个合理的默认值。
    【示例】
#  服务端开始监听端口
socket_server.listen(1)   # listen()方法内接收一个整数传参数,表示接受的链接数量

④接收客户端连接,获得连接对象
socket_server.accept()
accept方法:一个阻塞方法,用于在服务器端接受客户端的连接请求。调用该方法后,如果没有客户端尝试连接,accept() 方法会阻塞并等待直到有一个客户端尝试连接。
该方法返回一个二元元组 (conn, address),其中:

  • conn:一个新的 Socket 对象,用于与连接的客户端进行通信。
  • address:客户端的地址(IP 地址和端口),提供了连接的客户端的信息。

【示例】

# 等待客户端链接
conn,address=socket_server.accept()
"""
上面这行代码等价于
result:tuple=socket_server.accept()
conn=result[0]
address=result[1]
"""

【分析】
accept方法返回的是二元元组 (conn, address),可以通过变量1,变量2=socket_server.accept()的形式直接接收二元元组内的两个元素。

⑤接收客户端发送的消息
conn.recv(bytes)

  • recv方法:一个阻塞方法,用于接收连接中发来的数据。如果接收到的数据小于指定的字节数,方法将返回已接收的数据;如果没有数据可接收,程序会等待,直到有数据到达为止。
  • 参数bytes: 一个 int 整数,指定要接收的最大字节数。

【注意】
recv方法通过conn调用而不是socket_server调用。因为conn是专用于与特定客户端进行通信的 Socket 对象,而conn是用于监听和接受连接的服务器 Socket。
【示例】

data=conn.recv(1024).decode("UTF-8")
  • recv()方法接收的参数为缓冲区大小,一般给1024即可。
  • recv()方法的返回值为一个字节数组,即bytes对象,不是字符串,可以通过decode()方法进行UTF-8编码,将字节数组转换为字符串对象。

⑥回复客户端信息
conn.send(data)

  • send方法:用于将数据发送给连接的客户端
  • 参数data: 一个字节序列(bytes 对象),表示要发送的数据。
    【示例】
# 通过conn(客户端当次连接对象),调用send方法可以回复消息
conn.send(msg.encode("UTF-8"))

在这个示例中,conn.send() 方法接收的参数是通过 encode(“UTF-8”) 将字符串转换为字节后的结果。这样,客户端才能正确接收和处理该信息。

⑦关闭连接
conn(客户端当次连接对象)和socket_server对象调用close方法,关闭连接。
conn.close()
socket_server.close()

⑧测试
下载网络调试助手作为客户端进行测试。
下载地址:https://github.com/nicedayzhu/netAssist/releases
在这里插入图片描述
服务端代码示例:

# 导包
import socket
# 创建socket对象
socket_server=socket.socket()
# 绑定socket_server到指定IP和地址
socket_server.bind(("localhost",8888))
#  服务端开始监听端口
socket_server.listen(1)   # listen()方法内接收一个整数传参数,表示接受的链接数量

# 等待客户端链接
conn,address=socket_server.accept()
print(f"接收到了客户端的链接,客户端信息为{address}")

while True:
    # 接收客户端连接,获得连接对象
    data=conn.recv(1024).decode("UTF-8")
    print(f"客户端发来的消息:{data}")
    
    # 通过conn(客户端当次连接对象),调用send方法可以回复消息
    msg=input("请输入回复客户端的信息:")
    if msg=='exit':
        break
    conn.send()

# 关闭连接
conn.close()
socket_server.close()

运行服务端代码
在这里插入图片描述
双击打开安装好的网络调试助手netAssist
在这里插入图片描述
配置netAssist相关环境,点击“开始连接”
在这里插入图片描述
连接成功
在这里插入图片描述
客户端发送消息
在这里插入图片描述
服务端成功接收消息
在这里插入图片描述
输入 “exit”,代码中的 break 语句会被执行,从而终止当前的循环,服务端会停止向客户端发送消息,并最终结束程序。

三、Socket客户端编程

①导包并创建socket对象
import socket
socket_client=socket.socket()

②连接到服务端
socket_client.connect((host, port))
connect()方法:一个阻塞方法,用于客户端连接到服务器。如果服务器没有响应,connect() 会阻塞,直到连接成功或发生超时。
【示例】

# 绑定socket_server到指定IP和地址
socket_client.connect(("localhost",8888))

③发送消息
socket_client.send(data)

# 发送消息
socket_client.send("你好呀".encode("UTF-8"))

④接收服务端消息
socket_client.recv(bytes)

# 接收返回信息
recv_data=socket_client.recv(1024)   # 1024为缓冲区大小,一般给1024即可

⑤关闭链接
socket_client.close()

四、服务端与客户端相互通讯

服务端示例代码:

# 导包
import socket
# 创建socket对象
socket_server=socket.socket()
# 绑定socket_server到指定IP和地址
socket_server.bind(("localhost",8888))
#  服务端开始监听端口
socket_server.listen(1)   # listen()方法内接收一个整数传参数,表示接受的链接数量

# 等待客户端链接
conn,address=socket_server.accept()
print(f"接收到了客户端的链接,客户端信息为{address}")

while True:
    # 接收客户端连接,获得连接对象
    data=conn.recv(1024).decode("UTF-8")
    print(f"客户端发来的消息:{data}")
    
    # 通过conn(客户端当次连接对象),调用send方法可以回复消息
    msg=input("请输入回复客户端的信息:")
    if msg=='exit':
        break
    conn.send()

# 关闭连接
conn.close()
socket_server.close()

客户端示例代码:

# 导包
import socket
# 创建socket对象
socket_client=socket.socket()
# 绑定socket_server到指定IP和地址
socket_client.connect(("localhost",8888))
# 发送消息
socket_client.send("你好呀".encode("UTF-8"))
while True:
    # 发送消息
    msg = input("请输入要给服务端发送的消息:")
    if msg == 'exit':
        break
    socket_client.send(msg.encode("UTF-8"))
    # 接收返回消息
    recv_data = socket_client.recv(1024)        # 1024是缓冲区的大小,一般1024即可。 同样recv方法是阻塞的
    print(f"服务端回复的消息是:{recv_data.decode('UTF-8')}")
# 关闭链接
socket_client.close()

先启动服务端再启动客户端。
服务端接收到客户端发来的信息并回复客户端。
在这里插入图片描述
客户端接收到服务端发来的信息并回复服务端。
在这里插入图片描述
输入 “exit”,代码中的 break 语句会被执行,从而终止当前的循环,服务端会停止向客户端发送消息,并最终结束程序。

在这里插入图片描述

  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值