Socket
ocket (简称 套接字) 是进程之间通信一个工具,好比现实生活中的插座,所有的家用电器要想工作都是基于插座进行,进程之间想要进行网络通信需要socket。
Socket负责进程之间的网络数据传输,好比数据的搬运工。
客户端和服务端
2个进程之间通过Socket进行相互通讯,就必须有服务端和客户端
Socket服务端:等待其它进程的连接、可接受发来的消息、可以回复消息
Socket客户端:主动连接服务端、可以发送消息、可以接收回复
Socket服务端编程
主要分为如下几个步骤:
1. 创建socket对象
import socket # 创建Socket对象 socket_server = socket.socket()
2. 绑定socket_server到指定IP和地址
# 绑定socket_server到指定的ip和地址 socket_server.bind(host, port)
3. 服务端开始监听端口
# 服务端监听端口 socket_server.listen(backlog) # listen方法内接受一个整数传参数, # backlog为int整数,表示接受的链接数量,超出的会等待,可以不填,不填会自动设置一个合理值
4. 接收客户端连接,获得连接对象
# 接受客户端连接,获得连接对象 # result: tuple = socket_server.accept() # conn = result[0] # 客户端和服务端的链接对象 # address = result[1] # 客户端的地址信息 conn, address = socket_server.accept() print(f"接收到了客户端的链接,客户端的信息是:{address}") # accept()方法,是阻塞的方法,等待客户端的链接,如果没有链接,就卡在这一行不向下执行了 # accept方法返回的是二元元组(链接对象, 客户端地址信息) # 可以通过 变量1, 变量2 = socket_server.accept()的形式,直接接受二元元组内的两个元素
5. 客户端连接后,通过recv方法,接收客户端发送的消息
while True: # 接受客户端信息,要使用客户端和服务端的本次链接对象,而非socket_server对象 data: str = conn.recv(1024).decode("UTF-8") # recv接受的参数是缓冲区大小,一般给1024即可 # recv方法的返回值是一个字节数组也就是bytes对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象 print(f"客户端发来的消息是:{data}")
6. 通过conn(客户端当次连接对象),调用send方法可以回复消息
while True: # 接受客户端信息,要使用客户端和服务端的本次链接对象,而非socket_server对象 data: str = conn.recv(1024).decode("UTF-8") # recv接受的参数是缓冲区大小,一般给1024即可 # recv方法的返回值是一个字节数组也就是bytes对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象 print(f"客户端发来的消息是:{data}") # 发送回复消息 msg = input("请输入你要和客户端回复的消息:") if msg == 'exit': break conn.send(msg.encode("UTF-8"))
7. conn(客户端当次连接对象)和socket_server对象调用close方法,关闭连接
# 关闭链接 conn.close() socket_server.close()
实现服务端并结合客户端进行测试
下载网络调试助手作为客户端
https://github.com/nicedayzhu/netAssist/releases
Socket客户端编程
主要分为如下几个步骤:
1. 创建socket对象
2. 连接到服务端
3. 发送消息
4. 接收返回消息
5. 关闭链接
服务端客户端相互通讯
结合上一节学习的服务端代码,以及当前学习的客户端代码。
两者均运行起来,进行相互通讯。
"""
演示Socket服务端开发
"""
import socket
# 创建Socket对象
socket_server = socket.socket()
# 绑定ip地址和端口
socket_server.bind(("localhost", 8888))
# 监听端口
socket_server.listen(1)
# listen方法内接受一个整数传参数,表示接受的链接数量
# 等待客户端链接
# result: tuple = socket_server.accept()
# conn = result[0] # 客户端和服务端的链接对象
# address = result[1] # 客户端的地址信息
conn, address = socket_server.accept()
# accept方法返回的是二元元组(链接对象, 客户端地址信息)
# 可以通过 变量1, 变量2 = socket_server.accept()的形式,直接接受二元元组内的两个元素
# accept()方法,是阻塞的方法,等待客户端的链接,如果没有链接,就卡在这一行不向下执行了
print(f"接收到了客户端的链接,客户端的信息是:{address}")
while True:
# 接受客户端信息,要使用客户端和服务端的本次链接对象,而非socket_server对象
data: str = conn.recv(1024).decode("UTF-8")
# recv接受的参数是缓冲区大小,一般给1024即可
# recv方法的返回值是一个字节数组也就是bytes对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象
print(f"客户端发来的消息是:{data}")
# 发送回复消息
msg = input("请输入你要和客户端回复的消息:")
if msg == 'exit':
break
conn.send(msg.encode("UTF-8"))
# 关闭链接
conn.close()
socket_server.close()
"""
演示Socket客户端开发
"""
import socket
# 创建socket对象
socket_client = socket.socket()
# 连接到服务端
socket_client.connect(("localhost", 8888))
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()
总结:
客户端和服务端的相同点:
import socket
# 创建socket对象
socket_client = socket.socket()
客户端和服务端的不同点:
- 服务端:
# 绑定ip地址和端口
socket_server.bind(("localhost", 8888))
# 监听端口
socket_server.listen(1)
- 服务端先接收消息再发送消息
- 客服端:
# 连接到服务端
socket_client.connect(("localhost", 8888))
- 客服端先发送消息再接收消息