message-io
是一个快速且易于使用的事件驱动网络库。该库在内部处理操作系统套接字,并向用户提供简单的事件消息 API。它还允许您遵循一些规则为您自己的传输协议创建适配器,将繁琐的异步和线程管理委托给库。
如果您在使用该库时发现问题或者您有改进它的想法,请随时提出问题。欢迎任何贡献!请记住:咖啡因越多,工作效率越高!
管理套接字很困难,因为您需要应对线程、并发、全双工、编码、来自操作系统的 IO 错误(在某些情况下确实很难理解)等。如果您使用非阻塞套接字,它增加了新的复杂性:同步来自操作系统的异步事件。
message-io
提供了一种简单的方法来处理所有上述问题,使它们对您(想要创建具有自己的问题的应用程序)的程序员来说是透明的。为此,该库为您提供了一个简单的 API,其中包含两个需要理解的概念:消息(您发送和接收的数据)和端点(该数据的接收者)。这种抽象还提供了独立于所使用的传输协议而使用相同 API 的可能性。您可以在一行中更改应用程序的传输。
wasm
但已计划)。NodeHandler
来管理所有连接(连接、监听、删除、发送)和信号(计时器、优先级)。NodeListener
用于处理来自网络的所有信号和事件。std::io::Error
。message-io
没有您需要的传输?轻松添加适配器。 添加到您的Cargo.toml
(默认情况下包含所有运输):
[ dependencies ]
message-io = " 0.18 "
如果您只想使用可用传输电池的子集,则可以通过其关联功能tcp
、 udp
和websocket
来选择它们。例如,为了仅包含TCP和UDP ,请添加到您的Cargo.toml
:
[ dependencies ]
message-io = { version = " 0.18 " , default-features = false , features = [ " tcp " , " udp " ] }
以下示例是最简单的服务器,它从客户端读取消息并使用相同的消息响应它们。它能够同时为3种不同的协议提供“服务”。
use message_io :: node :: { self } ;
use message_io :: network :: { NetEvent , Transport } ;
fn main ( ) {
// Create a node, the main message-io entity. It is divided in 2 parts:
// The 'handler', used to make actions (connect, send messages, signals, stop the node...)
// The 'listener', used to read events from the network or signals.
let ( handler , listener ) = node :: split :: < ( ) > ( ) ;
// Listen for TCP, UDP and WebSocket messages at the same time.
handler . network ( ) . listen ( Transport :: FramedTcp , "0.0.0.0:3042" ) . unwrap ( ) ;
handler . network ( ) . listen ( Transport :: Udp , "0.0.0.0:3043" ) . unwrap ( ) ;
handler . network ( ) . listen ( Transport :: Ws , "0.0.0.0:3044" ) . unwrap ( ) ;
// Read incoming network events.
listener . for_each ( move |event| match event . network ( ) {
NetEvent :: Connected ( _ , _ ) => unreachable ! ( ) , // Used for explicit connections.
NetEvent :: Accepted ( _endpoint , _listener ) => println ! ( "Client connected" ) , // Tcp or Ws
NetEvent :: Message ( endpoint , data ) => {
println ! ( "Received: {}" , String :: from_utf8_lossy ( data ) ) ;
handler . network ( ) . send ( endpoint , data ) ;
} ,
NetEvent :: Disconnected ( _endpoint ) => println ! ( "Client disconnected" ) , //Tcp or Ws
} ) ;
}
以下示例显示了可以连接到先前服务器的客户端。它每秒向服务器发送一条消息并监听其回显响应。将Transport::FramedTcp
更改为Udp
或Ws
将更改使用的底层传输。
use message_io :: node :: { self , NodeEvent } ;
use message_io :: network :: { NetEvent , Transport } ;
use std :: time :: Duration ;
enum Signal {
Greet ,
// Any other app event here.
}
fn main ( ) {
let ( handler , listener ) = node :: split ( ) ;
// You can change the transport to Udp or Ws (WebSocket).
let ( server , _ ) = handler . network ( ) . connect ( Transport :: FramedTcp , "127.0.0.1:3042" ) . unwrap ( ) ;
listener . for_each ( move |event| match event {
NodeEvent :: Network ( net_event ) => match net_event {
NetEvent :: Connected ( _endpoint , _ok ) => handler . signals ( ) . send ( Signal :: Greet ) ,
NetEvent :: Accepted ( _ , _ ) => unreachable ! ( ) , // Only generated by listening
NetEvent :: Message ( _endpoint , data ) => {
println ! ( "Received: {}" , String :: from_utf8_lossy ( data ) ) ;
} ,
NetEvent :: Disconnected ( _endpoint ) => ( ) ,
}
NodeEvent :: Signal ( signal ) => match signal {
Signal :: Greet => { // computed every second
handler . network ( ) . send ( server , "Hello server!" . as_bytes ( ) ) ;
handler . signals ( ) . send_with_timer ( Signal :: Greet , Duration :: from_secs ( 1 ) ) ;
}
}
} ) ;
}
克隆存储库并测试Ping Pong示例(类似于README示例,但更丰富)。
运行服务器:
cargo run --example ping-pong server tcp 3456
运行客户端:
cargo run --example ping-pong client tcp 127.0.0.1:3456
您可以通过更改传输、运行多个客户端、断开它们的连接等来使用它。请在此处查看更多信息。
message-io
没有的传输协议?添加适配器! message-io
提供两种API。作为库用户与message-io
本身进行对话的用户 API ,以及那些想要将其协议适配器添加到库中的内部适配器 API 。
如果可以在mio
之上构建传输协议(大多数现有协议库都可以),那么您可以非常轻松地将其添加到message-io
中:
在src/adapters/<my-transport-protocol>.rs
中添加适配器文件,以实现您在此处找到的特征。它只包含 8 个需要实现的强制函数(参见模板),并且需要大约 150 行代码来实现一个适配器。
在 src/network/transport.rs 中的Transport
枚举中添加一个新字段来注册您的新适配器。
就这样。您可以像其他传输一样将新传输与message-io
API 一起使用。
哎呀!又一步:发出Pull 请求,以便每个人都可以使用它:)
message-io
开源项目您的出色项目使用message-io
吗?发出拉取请求并将其添加到列表中!
message-io
主要目标是让事情变得简单。这很好,但有时这种观点可能会使本来就复杂的事情变得更加复杂。
例如, message-io
允许在不使用async/await
模式的情况下处理异步网络事件。它降低了处理来自网络的收入消息的复杂性,这很棒。然而,读取异步消息的应用程序也倾向于对这些事件执行异步任务。这种异步继承可以轻松地传播到整个应用程序,如果没有异步/等待模式,则很难维护或扩展。在这种情况下,也许tokio
可能是更好的选择。您需要处理更多低级网络内容,但您会在组织和线程/资源管理方面有所收获。
关于message-io
的节点使用,可能会发生类似的问题。由于节点可以独立用作客户端/服务器或两者,因此您可以轻松地开始制作对等应用程序。其实这也是message-io
的意图之一。然而,如果您的目标规模较大,就会出现与此模式相关的问题需要处理,而libp2p
等库附带了大量工具来帮助实现该目标。
当然,这并不是对库使用的免责声明(我使用它!),更多的是诚实地了解其功能,并根据您的需求引导您使用正确的工具。
总结一下:
message-io
让问题变得更简单!tokio
、 libp2p
或其他,以更好地控制它。