python编写Socket程序
文章目录
- 编写非阻塞的TCP连接程序
- 编写UDP的socket程序
- 创建连接
- 发送数据
- 多线程管理udp
编写非阻塞的TCP连接程序
下面代码使用了select模块来管理多个 socket 连接,server_socket.setblocking(0)将服务器 socket 设置为非阻塞模式 ,在接收数据时,若没有数据可读,会捕获EAGAIN或EWOULDBLOCK错误并继续循环。
import socket
import select
def non_blocking_tcp_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_address = ('localhost', 10000)
server_socket.bind(server_address)
server_socket.listen(1)
# 设置为非阻塞模式
server_socket.setblocking(0)
inputs = [server_socket]
print("Server is listening on {}:{}".format(*server_address))
while inputs:
readable, writable, exceptional = select.select(inputs, [], inputs)
for s in readable:
if s is server_socket:
connection, client_address = s.accept()
print(f"New connection from {client_address}")
connection.setblocking(0)
inputs.append(connection)
else:
try:
data = s.recv(1024)
if data:
print(f"Received from {s.getpeername()}: {data.decode()}")
s.sendall(b"Hello, client!")
else:
print(f"Closing connection from {s.getpeername()}")
inputs.remove(s)
s.close()
except socket.error as e:
if e.errno in (socket.errno.EAGAIN, socket.errno.EWOULDBLOCK):
continue
else:
print(f"Error: {e}")
inputs.remove(s)
s.close()
for s in exceptional:
print(f"Handling exceptional condition for {s.getpeername()}")
inputs.remove(s)
s.close()
if __name__ == "__main__":
non_blocking_tcp_server()
编写UDP的socket程序
UDP 是无连接的传输协议,相比 TCP 更简单。我将重新编写代码,展示如何使用 Python 实现 UDP 发送和接收报文,重点在于socket模块中 UDP 相关的函数调用。
import socket
def udp_send_receive():
# 创建UDP socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定地址和端口
server_address = ('localhost', 10001)
udp_socket.bind(server_address)
# 发送数据
message = "Hello, UDP!"
target_address = ('localhost', 10002)
udp_socket.sendto(message.encode(), target_address)
while True:
try:
# 接收数据
data, client_address = udp_socket.recvfrom(1024)
print(f"Received from {client_address}: {data.decode()}")
except socket.error as e:
print(f"Error: {e}")
if __name__ == "__main__":
udp_send_receive()
上述代码中,先创建 UDP socket 并绑定地址端口,然后向目标地址发送数据,接着进入循环持续接收数据。
这里说明一下UDP的调试,类型选择udp,端口是刚才代码中绑定的端口。
创建连接
发送数据
点创建,然后发送随便的内容
显示收到了数据
多线程管理udp
下面这个例子,是把收发放在不同的线程中进行运行。提高程序的并发性,我将引入threading模块来创建线程。
import socket
import threading
def udp_send(udp_socket, target_address):
message = "Hello, UDP!"
while True:
try:
udp_socket.sendto(message.encode(), target_address)
# 为了避免发送过于频繁,这里添加一个小的时间间隔,单位为秒
import time
time.sleep(1)
except socket.error as e:
print(f"Send Error: {e}")
def udp_receive(udp_socket):
while True:
try:
data, client_address = udp_socket.recvfrom(1024)
print(f"Received from {client_address}: {data.decode()}")
except socket.error as e:
print(f"Receive Error: {e}")
def main():
# 创建UDP socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定地址和端口
server_address = ('localhost', 10001)
udp_socket.bind(server_address)
target_address = ('localhost', 10002)
send_thread = threading.Thread(target=udp_send, args=(udp_socket, target_address))
receive_thread = threading.Thread(target=udp_receive, args=(udp_socket,))
send_thread.start()
receive_thread.start()
send_thread.join()
receive_thread.join()
if __name__ == "__main__":
main()