前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Socket网络编程

Socket网络编程

原创
作者头像
Heaven645
发布2024-08-17 01:03:33
540
发布2024-08-17 01:03:33
举报
文章被收录于专栏: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 是整数形式的端口号。

【示例】

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

③服务端开始监听端口

socket_server.listen(backlog)

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

④接收客户端连接,获得连接对象

socket_server.accept()

accept方法:一个阻塞方法,用于在服务器端接受客户端的连接请求。调用该方法后,如果没有客户端尝试连接,accept() 方法会阻塞并等待直到有一个客户端尝试连接。

该方法返回一个二元元组(conn, address),其中:

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

【示例】

代码语言:python
代码运行次数:0
复制
# 等待客户端链接
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。

【示例】

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

⑥回复客户端信息

conn.send(data)

  • send方法:用于将数据发送给连接的客户端# 通过conn(客户端当次连接对象),调用send方法可以回复消息 conn.send(msg.encode("UTF-8"))在这个示例中,conn.send() 方法接收的参数是通过 encode("UTF-8") 将字符串转换为字节后的结果。这样,客户端才能正确接收和处理该信息。
  • 参数data: 一个字节序列(bytes 对象),表示要发送的数据。 【示例】

⑦关闭连接

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

conn.close()

socket_server.close()

⑧测试

下载网络调试助手作为客户端进行测试。

下载地址https://github.com/nicedayzhu/netAssist/releases

服务端代码示例:

代码语言:python
代码运行次数:0
复制
# 导包
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() 会阻塞,直到连接成功或发生超时。

【示例】

代码语言:python
代码运行次数:0
复制
# 绑定socket_server到指定IP和地址
socket_client.connect(("localhost",8888))

③发送消息

socket_client.send(data)

代码语言:python
代码运行次数:0
复制
# 发送消息
socket_client.send("你好呀".encode("UTF-8"))

④接收服务端消息

socket_client.recv(bytes)

代码语言:python
代码运行次数:0
复制
# 接收返回信息
recv_data=socket_client.recv(1024)   # 1024为缓冲区大小,一般给1024即可

⑤关闭链接

socket_client.close()

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

服务端示例代码:

代码语言:python
代码运行次数:0
复制
# 导包
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()

客户端示例代码:

代码语言:python
代码运行次数:0
复制
# 导包
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 语句会被执行,从而终止当前的循环,服务端会停止向客户端发送消息,并最终结束程序。

思考:为什么服务端会比客户端多一个conn对象?

回答:服务端与客户端在通信中扮演着不同的角色。服务端需要接收来自多个客户端的连接,每当一个客户端连入时,服务端通过accept()方法创建一个新的连接对象conn,用于与该特定客户端进行数据交换。这样,服务端可以同时处理多个客户端的请求,而客户端每次只与一个服务端连接。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、Socket网络编程
  • 二、Socket服务端编程
  • 三、Socket客户端编程
  • 四、服务端与客户端相互通讯
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档