目录:
socket 是进行底层网络编程的核心工具,允许开发者直接控制数据包的发送与接收,从而实现自定义的网络协议和通信应用。
IP 地址和端口的组合叫做套接字,IP 可以找到一台联网的电脑,端口可以找到这台电脑上指定的程序。
Alice
Bob
现在 Alice 给 Bob 的维信发一条消息,知道 Bob 的 ip 地址 192.1.1.2 就可以找到 Bob 的电脑,知道 Bob 的微信端口是 100,就不会发消息错发给 QQ 了。
IP + 端口(Port) 是不同主机间进程进行通信的基本单位。
socket.socket() 创建套接字对象,函数需要指定两个关键参数:地址家族(Address Family)和套接字类型(Socket Type)。
地址家族:定义了网络地址的格式。
套接字类型:定义了数据传输的方式。
示例:
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
服务器端扮演被动的监听者角色,其标准流程如下:
import socket
# 创建 TCP 套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
client_socket.connect(('localhost', 9999))
# 发送消息,字符串需要编码为字节
message = 'Hello, Server!'
client_socket.sendall(message.encode())
# 接收回复(最多 1024 字节)
response = client_socket.recv(1024)
print(f'Received: {response.decode()}')
# 关闭连接
client_socket.close()
上述代码运行后,服务端会一直处于启动状态,等待客户端发来请求。
问题来了,客户端怎么找到这个服务端?
服务端可以理解成一个类似于 QQ 和微信的软件,启动服务端就相当于启动微信,服务端使用的 IP 是本地地址 localhost,端口号是 9999,有了 IP + 端口,客户端就可以连接服务端了,详情看下面客户端流程的示例。
客户端主动发起连接,流程更为简洁:
import socket
# 创建 TCP 套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
client_socket.connect(('localhost', 9999))
# 发送消息,字符串需要编码为字节
message = 'Hello, Server!'
client_socket.sendall(message.encode())
# 接收回复(最多 1024 字节)
response = client_socket.recv(1024)
print(f'Received: {response.decode()}')
# 关闭连接
client_socket.close()
开一个新的终端,运行上面代码,客户端会向服务端发送一条消息,切回运行服务端的终端,可以看到有打印从客户端传过来的消息。
在实际应用中,如聊天室,服务器需要同时处理多个客户端连接。这可以通过为每个连接创建一个独立的线程来实现。
import socket
import threading
# 用于存储所有活跃客户端连接的列表
clients = []
def broadcast(message, sender_client):
"""向除发送者外的所有客户端广播消息"""
for client in clients:
if client != sender_client:
try:
client.send(message)
except:
# 如果发送失败,移除该客户端
clients.remove(client)
client.close()
def handle_client(client):
"""处理单个客户端连接的线程函数"""
while True:
try:
message = client.recv(1024)
if message:
broadcast(message, client)
else:
# 接收到空消息,表示客户端断开
raise Exception("Client disconnected")
except:
# 发生异常,移除客户端并结束线程
if client in clients:
clients.remove(client)
client.close()
break
def receive():
"""主函数,接受新连接并启动处理线程"""
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 9999))
server_socket.listen()
print("Server started...")
while True:
client, addr = server_socket.accept()
print(f"Connected with {str(addr)}")
clients.append(client)
# 为每个新连接创建一个线程
thread = threading.Thread(target=handle_client, args=(client,))
thread.start()
if __name__ == "__main__":
receive()
↶ 返回首页 ↶