The jsonrpsee framework only provides HTTP and WebSocket server implementations by default. reth/ipc provides IPC server and client implementations. For scenarios that require TCP server implementation, this library provides both TCP server and client implementations.
- ✅ TCP server implementation
- ✅ TCP client implementation
- ✅ Support for both synchronous and asynchronous method registration
- ✅ Support for subscriptions
- ✅ Full JSON-RPC 2.0 protocol support
- ✅ Built on tokio async runtime
Add the dependency to your Cargo.toml:
[dependencies]
jsonrpsee-tcp = "0.1.0"
jsonrpsee = "0.24"
tokio = { version = "1.0", features = ["full"] }use jsonrpsee::types::Params;
use jsonrpsee_tcp::server::Builder;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server = Builder::new()
.register_method("say_hello", |params: Params, _ctx: &()| {
let name: String = params.one()?;
Ok(format!("Hello, {}!", name))
})?
.register_method("add", |params: Params, _ctx: &()| {
let params: (i32, i32) = params.parse()?;
Ok(params.0 + params.1)
})?
.build("127.0.0.1:9944".parse()?)
.await?;
println!("TCP server listening on {}", server.local_addr());
server.run().await?;
Ok(())
}use jsonrpsee_tcp::client::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::connect("127.0.0.1:9944".parse()?).await?;
// Call methods
let response: String = client.request("say_hello", vec!["World"]).await?;
println!("Response: {}", response);
let sum: i32 = client.request("add", vec![5, 3]).await?;
println!("Sum: {}", sum);
Ok(())
}use jsonrpsee::core::server::SubscriptionMessage;
use jsonrpsee::types::Params;
use jsonrpsee_tcp::server::Builder;
use tokio::time::{interval, Duration};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server = Builder::new()
.register_subscription(
"subscribe_hello",
"hello",
"unsubscribe_hello",
|_params, pending, _ctx, _ext| async move {
let sink = match pending.accept().await {
Ok(sink) => sink,
Err(_) => return,
};
let mut interval = interval(Duration::from_secs(2));
let mut counter = 0;
loop {
interval.tick().await;
counter += 1;
let message = format!("Hello #{}", counter);
if sink.send(SubscriptionMessage::from(message)).await.is_err() {
break;
}
if counter >= 10 {
break;
}
}
},
)?
.build("127.0.0.1:9945".parse()?)
.await?;
server.run().await?;
Ok(())
}Start the server:
cargo run --example serverRun the client in another terminal:
cargo run --example clientOr test using the nc command:
nc localhost 9944
{"jsonrpc":"2.0","method":"say_hello","params":["World"],"id":1}You can also run the subscription example:
cargo run --example subscription_serverBuilder::new()- Create a new server builderBuilder::register_method()- Register a synchronous methodBuilder::register_async_method()- Register an asynchronous methodBuilder::register_subscription()- Register a subscriptionBuilder::register_subscription_raw()- Register a subscription (raw version)Builder::merge()- Merge another RpcModuleBuilder::build()- Build and start the serverServer::run()- Run the server and accept connections
Client::connect()- Connect to a TCP serverClient::request()- Send a JSON-RPC requestClient::request_no_params()- Send a request without parameters
Uses the standard JSON-RPC 2.0 protocol, with each request and response separated by a newline character (\n).
Request format:
{"jsonrpc":"2.0","method":"method_name","params":[...], "id":1}Response format:
{"jsonrpc":"2.0","result":"...", "id":1}Error response:
{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error"},"id":1}MIT