3 个版本 (重大更新)

0.3.0 2024年7月8日
0.2.0 2024年6月26日
0.1.0 2024年6月25日

#1087网络编程

每月下载量 39
用于 warqueen_derive

MIT/Apache

44KB
550

Warqueen - 业余规模的网络 crate

基于消息,非异步,非阻塞。使用优秀的 Quinn 网络crate。

作为客户端,只需连接,发送消息,并在任何时候轮询接收到的消息,以非阻塞的方式,无需异步。作为服务器,同样的操作,并在任何时候轮询新的客户端连接。可以在几个循环中完成这些操作,API非常简单,易于理解和使用。

消息类型仅限于发送时可能的一个类型和接收时可能的一个类型,服务器和客户端交换这些类型角色。自然地,两者都使用枚举。

希望你喜欢 :3

用法

让我们从客户端开始。

首先定义两种消息类型,用于与服务器通信。客户端可以发送(到服务器)的类型和客户端可以接收(从服务器)的类型。

use serde::{Deserialize, Serialize};
use warqueen::{NetReceive, NetSend};

#[derive(Serialize, NetSend)]
enum MessageClientToServer {
	String(String),
}

#[derive(Deserialize, NetReceive)]
enum MessageServerToClient {
	String(String),
}

NetSendNetReceive derive 宏实现了同名的特质,允许标记的类型分别发送和接收。

然后创建 ClientNetworking 以连接到服务器,并在循环中使用它。

// Full type is `ClientNetworking<MessageClientToServer, MessageServerToClient>`.
let mut client = ClientNetworking::new(server_address);

loop {
	// Handling received messages from the server, as well as connection events.
	while let Some(event) = client.poll_event_from_server() {
		match event {
			ClientEvent::Message(message) => match message {
				MessageServerToClient::String(content) => println!("The server says \"{content}\""),
			},
			ClientEvent::Connected => println!("Connected"),
			ClientEvent::Disconnected => println!("Disconnected"),
		}
	}

	// Sending a message to the server.
	let message = MessageClientToServer::String("hiii :3".to_string());
	client.send_message_to_server(message);*

	sleep(Duration::from_millis(10));
}

请注意,连接不会立即建立,可能需要一些时间,当最终建立时,会有一个 ClientEvent::Connected 事件轮询以通知客户端。如果连接始终未建立,则不会轮询此类事件;在这种情况下,超时错误可能是相关的。

当是时候离开时,可以按如下方式正确关闭连接。

client.disconnect().wait_for_proper_disconnection();

请注意,如果 ClientNetworking::disconnect 调用不在主线程中,则返回的 DisconnectionHandle 应传递到主线程(例如通过通道),然后才应调用 DisconnectionHandle::wait_for_proper_disconnection。有关更多信息,请参阅文档。

服务器非常相似,它应该使用与客户端相同的信息类型,除了使用特性 NetSendNetReceive 实现相反(因为服务器发送时客户端接收,反之亦然)(只需交换 derive,包括 serde)。如果服务器和客户端使用相同类型定义,那就更好了:两种类型都可以实现这两种特性(#[derive(Serialize, Deserialize, NetSend, NetReceived)])。

然后创建 ServerListenerNetworking,用于监听想要连接的新客户端,并在循环中使用它。

// Full type is `ServerListenerNetworking<MessageServerToClient, MessageClientToServer>`.
let server_listener = ServerListenerNetworking::new(desired_port);
let mut clients = vec![];

loop {
	// Handling new clients connections.
	while let Some(client) = server_listener.poll_client() {
		// Client type is `ClientOnServerNetworking<MessageServerToClient, MessageClientToServer>`.
		println!("Connected to a client at {}", client.client_address());
		clients.push(client);
	}

	// Handling clients...

	sleep(Duration::from_millis(10));
}

ServerListenerNetworking::poll_client 查询的客户端类型为 ClientOnServerNetworking,基本上是 ClientNetworking 的服务器端等效物。在客户端程序中,对于每个连接的 ClientNetworking,服务器程序中都有一个相应的 ClientOnServerNetworking

// Handling received messages as well as connection events from all clients.
for (index, client) in clients.iter().enumerate() {
	while let Some(event) = client.poll_event_from_client() {
		match event {
			ClientOnServerEvent::Message(message) => match message {
				MessageClientToServer::String(content) => {
					println!("Client {index} says \"{content}\"");
				},
			},
			ClientOnServerEvent::Disconnected => {
				println!("Client {index} disconnected");
			},
		}
	}
}

// Sending a message to a client.
let message = MessageServerToClient::String("nyaa~".to_string());
clients[some_index_whatever].send_message_to_client(message);

注意,服务器端 ClientEvent::Connected 事件的等效是 ServerListenerNetworking::poll_client 返回一个连接到客户端,不需要 ClientOnServerEvent::Connected,因为 ClientOnServerNetworking 在创建时已经连接到客户端。

断开连接与客户端相同,它还带有 DisconnectionHandle(对于每次断开连接),以便在不在主线程上断开连接时特别小心地将它带到主线程。

clients[some_index_whatever].disconnect().wait_for_proper_disconnection();

缩放

业余级别!只是一个围绕 Quinn(最佳 Rust 网络库?)的小包装,以获得我喜欢的 API。它可能适合游戏网络,希望如此!至少我在我的游戏中使用它。

请参阅 待办事项列表 以获取潜在的未来功能。也欢迎贡献力量!

请注意,任何有意提交以供您在 Apache-2.0 许可证定义的工作中包含的贡献,都应按以下方式双授权,没有任何附加条款或条件。

许可证

版权 2024 Jeanne DEMOUSSEL。

本项目受以下任一许可证的许可:

任选其一。

依赖项

~14–24MB
~437K SLoC