Giter Site home page Giter Site logo

ws-tool's Introduction

ws-tool

An easy to use websocket client/server toolkit, supporting blocking/async IO.

feature matrix

IO type split proxy tls buffered stream deflate use as client use as server
blocking
async

web framework integration

For tls connection, ws-tool support both native-tls and rustls, ws-tool also support simd utf checking for faster utf8 string checking.

It's tested by autobaha test suit. see test report of 4 example

usage

Every example can be run with

cargo run --example <example_name> --all-features

command.

See

  • examples/echo_async_server for building a websocket echo server with self signed cert.
  • examples/echo demonstrates how to connect to a server.
  • binance demonstrates how to connect to wss server via http/socks proxy
  • poem demonstrates how to integrate with poem web framework.
  • autobaha_xxx_client are autobaha test suit client
  • bench_xxx are benchmark server examples, showing how to control read/write buffer or other low level config

run autobahn testsuite

start test server

./script/start_autobahn_server.sh

run test on other terminal

cargo ac
cargo aac
cargo adc
cargo aadc

report files should be under test_reports dir.

performance

Performance is a complex issue, and a single performance indicator is not enough to describe the performance of a certain library. Here we only compare QPS as a brief description of ws-tool performance

My test machine is i9-12900k and 32GB, 3200MHz ddr4, and load test client is load_test

Roughly compare with EchoSever example, tungstenite

The following are the benchmark(1 connection only) results, there is no tungstenite with buffered stream test case, because there tungstenite does not work well with buffered stream, fastwebsockets is not added, because it's performance is very bad in this test case, if you know how to improve fastwebsockets performance, please open a PR! tokio runtime use current_thread flavor.

300 bytes payload size, 100000000 messages

cargo lt -- -b 819200 -p 300 --count 100000 -t 1 <url>
server count Duration(ms) Message/sec
uWebSocket 100000000 10014 9986019.57
tungstenite 100000000 21566 4636928.50
bench_server(8k) 100000000 29597 3378720.82
bench_server(800k) 100000000 9320 10729613.73
bench_async_server(8k) 100000000 17846 5603496.58
bench_async_server(800k) 100000000 14006 7139797.23

1M bytes payload size, 100000 messages

cargo lt -- -p 1048576 --count 100 -t 1 <url>
server count Duration(ms) Message/sec
uWebSocket 100000 34195 2924.40
tungstenite 100000 40139 2491.34
bench_server(no buffer) 100000 16405 6095.70
bench_server(8k) 100000 17240 5800.46
bench_async_server(no buffer) 100000 17190 5817.34
bench_async_server(8k) 100000 17027 5873.03

you can try more combinations with load_test tool

http header style

for multiple extension/protocol, ws-tool prefer to use multiple header with the same name, instead of "," separated value. but ws-tool still try to parse extension/protocol from "," separated header value.

REF

ws-tool's People

Contributors

dxvid-pts avatar jordy25519 avatar parasyte avatar privaterookie avatar pymongo avatar zhenpingfeng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

ws-tool's Issues

Ntex/axum integration

Is it possible to integrate your crate with frameworks such as ntex or axum? It would be great to see examples

InsufficientLen error

Hello. Thanks for such performant and easy-to-use library.
I'm trying to adapt it for using with large streams from Binance and getting an error: Close code: 1008, error: InsufficientLen(2). So 5-10 seconds it works fine, I see messages from websocket. But after that I see this error.

Err(e) => match e {
            WsError::ProtocolError { close_code, error } => {
              println!("Close code: {close_code:?}, error: {error:?}");
              break
            }
            _ => {
              println!("Something strange happened with the websocket");
            }
          }

I'm just doing client.receive().await without sending anything. Do you known what can be a cause?

I use this url which produce this error after a couple of seconds:

wss://fstream.binance.com:443/stream?streams=rayusdt@bookTicker/api3usdt@bookTicker/sushiusdt@bookTicker/cvcusdt@bookTicker/btsusdt@bookTicker/ftmbusd@bookTicker/hotusdt@bookTicker/trxbusd@bookTicker/zrxusdt@bookTicker/qtumusdt@bookTicker/iotausdt@bookTicker/btcbusd@bookTicker/wavesusdt@bookTicker/adausdt@bookTicker/litusdt@bookTicker/xtzusdt@bookTicker/bnbusdt@bookTicker/darusdt@bookTicker/hntusdt@bookTicker/etcusdt@bookTicker/xmrusdt@bookTicker/yfiusdt@bookTicker/fttbusd@bookTicker/ethusdt@bookTicker/aliceusdt@bookTicker/alphausdt@bookTicker/woousdt@bookTicker/sfpusdt@bookTicker/reefusdt@bookTicker/batusdt@bookTicker/dogeusdt@bookTicker/trxusdt@bookTicker/rlcusdt@bookTicker/storjusdt@bookTicker/snxusdt@bookTicker/1000xecusdt@bookTicker/dotbusd@bookTicker/audiousdt@bookTicker/nearbusd@bookTicker/xlmusdt@bookTicker/apebusd@bookTicker/iotxusdt@bookTicker/neousdt@bookTicker/unfiusdt@bookTicker/sandusdt@bookTicker/dashusdt@bookTicker/kavausdt@bookTicker/runeusdt@bookTicker/apeusdt@bookTicker/ctkusdt@bookTicker/linkusdt@bookTicker/celrusdt@bookTicker/bnxusdt@bookTicker/opusdt@bookTicker/rsrusdt@bookTicker/adabusd@bookTicker/dgbusdt@bookTicker/sklusdt@bookTicker/renusdt@bookTicker/lptusdt@bookTicker/jasmyusdt@bookTicker/tomousdt@bookTicker/mtlusdt@bookTicker/ltcusdt@bookTicker/dodobusd@bookTicker/egldusdt@bookTicker/ksmusdt@bookTicker/bnbbusd@bookTicker/ontusdt@bookTicker/vetusdt@bookTicker/imxusdt@bookTicker/trbusdt@bookTicker/manausdt@bookTicker/flowusdt@bookTicker/cotiusdt@bookTicker/chrusdt@bookTicker/bakeusdt@bookTicker/avaxbusd@bookTicker/grtusdt@bookTicker/flmusdt@bookTicker/galusdt@bookTicker/galabusd@bookTicker/maskusdt@bookTicker/eosusdt@bookTicker/ognusdt@bookTicker/ethusdt_220624@bookTicker/galbusd@bookTicker/balusdt@bookTicker/stmxusdt@bookTicker/dentusdt@bookTicker/kncusdt@bookTicker/srmusdt@bookTicker/enjusdt@bookTicker/c98usdt@bookTicker/zenusdt@bookTicker/atomusdt@bookTicker/nearusdt@bookTicker/solbusd@bookTicker/ensusdt@bookTicker/bchusdt@bookTicker/atausdt@bookTicker/iostusdt@bookTicker/hbarusdt@bookTicker/luna2busd@bookTicker/zecusdt@bookTicker/1000shibusdt@bookTicker/tlmbusd@bookTicker/antusdt@bookTicker/ethbusd@bookTicker/galausdt@bookTicker/aaveusdt@bookTicker/gtcusdt@bookTicker/algousdt@bookTicker/lrcusdt@bookTicker/avaxusdt@bookTicker/arpausdt@bookTicker/celousdt@bookTicker/roseusdt@bookTicker/maticusdt@bookTicker/1inchusdt@bookTicker/mkrusdt@bookTicker/peopleusdt@bookTicker/ancbusd@bookTicker/thetausdt@bookTicker/uniusdt@bookTicker/linausdt@bookTicker/arusdt@bookTicker/rvnusdt@bookTicker/filusdt@bookTicker/nknusdt@bookTicker/klayusdt@bookTicker/defiusdt@bookTicker/compusdt@bookTicker/btcdomusdt@bookTicker/solusdt@bookTicker/btcusdt@bookTicker/omgusdt@bookTicker/icxusdt@bookTicker/icpbusd@bookTicker/blzusdt@bookTicker/gmtusdt@bookTicker/ftmusdt@bookTicker/bandusdt@bookTicker/xrpbusd@bookTicker/dogebusd@bookTicker/xrpusdt@bookTicker/fttusdt@bookTicker/sxpusdt@bookTicker/crvusdt@bookTicker/belusdt@bookTicker/dotusdt@bookTicker/xemusdt@bookTicker/gmtbusd@bookTicker/oneusdt@bookTicker/1000luncbusd@bookTicker/zilusdt@bookTicker/axsusdt@bookTicker/dydxusdt@bookTicker/oceanusdt@bookTicker/chzusdt@bookTicker/ankrusdt@bookTicker/duskusdt@bookTicker/btcusdt_220624@bookTicker/ctsiusdt@bookTicker

Using this url with OkHttp client (Java VM) without any issues.

Help wanted: Create Node.js Bindings

Hi there, I am trying to create Node.js bindings for this library. Websockets are in high demand in Node.js & Javascript environments, so an npm package for this package would be really helpful.
Currently, uWebsockets is the fastest package in javascript environment, but this package can become a good competitor.

I tried to create bindings using napi-rs package template but got stuck with the Rust code. If the repo owner or someone knowledgable in Rust can help me, we can achieve this.

I managed to create a websocket connection using this and napi-rs but creating an API compatible with other websocket packages looks more challenging.

So, feel free to reply here or reach me at [email protected] if you want to help me.

tokio version conflict

Execution failed (exit code 101).
/Users/raphaelsoul/.cargo/bin/cargo metadata --verbose --format-version 1 --all-features
stdout :     Updating `https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index` index
error: failed to select a version for `tokio`.
    ... required by package `async-http-proxy v1.0.0`
    ... which is depended on by `ws-tool v0.2.0`
    ... which is depended on by `synchronizer v0.1.0 (/Users/raphaelsoul/projects/github.com/raphaelsoul/prophet/synchronizer)`
    ... which is depended on by `cmd v0.1.0 (/Users/raphaelsoul/projects/github.com/raphaelsoul/prophet/cmd)`
versions that meet the requirements `~1.0.2` are: 1.0.3, 1.0.2

all possible versions conflict with previously selected packages.

  previously selected package `tokio v1.8.1`
    ... which is depended on by `synchronizer v0.1.0 (/Users/raphaelsoul/projects/github.com/raphaelsoul/prophet/synchronizer)`
    ... which is depended on by `cmd v0.1.0 (/Users/raphaelsoul/projects/github.com/raphaelsoul/prophet/cmd)`

failed to select a version for `tokio` which could resolve this conflict

stderr : 

Load test is crashing on start

cargo lt -- -p 300 --count 50000 -t 1 'ws://localhost:9002'
    Finished release [optimized] target(s) in 0.20s
     Running `target/release/examples/load_test -p 300 --count 50000 -t 1 'ws://localhost:9002'`
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: IOError(Os { code: 54, kind: ConnectionReset, message: "Connection reset by peer" })', examples/load_test.rs:96:41
thread 'note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: IOError(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })', examples/load_test.rs:89:58
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: Any { .. }', examples/load_test.rs:99:53

Bitget got 403 Forbidden

Binance example works fine, however, when I was trying to connect to bitget I got 403 forbidden.

Websocat works fine.

websocat wss://ws.bitget.com/mix/v1/stream # Using cli tool successfully connected, and then sending some subscribe messages

> {"op":"subscribe","args":[{"instType":"mc","channel":"ticker","instId":"BTCUSDT"},{"instType":"mc","channel":"candle1m","instId":"BTCUSDT"}]}

Curl with default http2 got 403 too.

curl https://ws.bitget.com/mix/v1/stream \
 -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Connection: Upgrade" \
  -H "Sec-WebSocket-Key: Z29yYWRkdQo=" # Get 403 Forbidden

Curl with http 1.1 works fine.

curl --http1.1 https://ws.bitget.com/mix/v1/stream \
 -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Connection: Upgrade" \
  -H "Sec-WebSocket-Key: Z29yYWRkdQo=" # Works

I suspect the reason is because of http2? But then I saw the issue #14
I have already tried actix-web, tokio-tungstenite and fastwebsockets, really need some help here, thank you.

client send nul/zero byte array in 0.9 while 0.7 would not, it is a regression

my server is axum 0.6, client is ws-tool, When I update from 0.7 to 0.9, axum ws server receiver wired nul/zero bytes array

&msg = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
thread 'manage' panicked at ': Error("expected value", line: 1, column: 1)'
async fn kernel_ws_socket_handler(socket: axum::extract::ws::WebSocket, ctx: AppContext, kernel_info: KernelInfo) {
    let (mut ws_write, mut ws_read) = socket.split();
    loop {
        tokio::select! {
            msg_res_opt = ws_read.next() => {
                let msg_res = match msg_res_opt {
                    Some(msg_res) => msg_res,
                    None => {
                        tracing::warn!("EOF");
                        break;
                    }
                };
                let msg = match msg_res {
                    Ok(msg) => msg,
                    Err(err) => {
                        // e.g. Protocol(ResetWithoutClosingHandshake)
                        tracing::error!("kernel disconnect! {err}");
                        break;
                    }
                };
                let msg = match msg {
                    Message::Text(msg) => {
                        msg
                    },
                    Message::Ping(_) => {
                        if ws_write.send(Message::Pong(Vec::new())).await.is_err() {
                            tracing::error!("send pong back fail! break");
                            break;
                        }
                        continue;
                    }
                    Message::Close(_) => break,
                    _ => continue,
                };
                dbg!(msg.is_empty());
                dbg!(&msg);
                let msg = serde_json::from_str::<Message>(&msg).expect(&msg);
                // let msg = kernel_msg::Message::from_json(&msg.bytes().to_vec());
                rsp_tx.send(msg).unwrap();
            }
        }
    }

client:

 let socket=   ws_tool::ClientBuilder::new()
        .connect(url.parse().expect(&url), StringCodec::check_fn)
        .unwrap();
let (mut ws_r, mut ws_w) = socket.split();
//...
                        let rsp = serde_json::to_string(&rsp).unwrap();
                        if let Err(err) = ws_w.send(rsp) {
                            error!("{err}");
                        }

I rollback from 0.9 to 0.7 and works ok

Cant reconnect when IOError(early eof)/OpCode::Close occurs

Cannot reconnect by calling client.handshake().await.
receives HandShakeFailed("incomplete handshake response")

seems to be caused by TCP proxy stream not reconnect in method handshake.

Considering add a reconnect method on Connection struct to perform a full connection establish progress?

reconnecting... Connection { uri: wss://fstream.binance.com/stream?streams=ethusdt@ticker, mode: WSS, codec: DefaultFrameCodec { check_rsv: true }, stream: Tls(TlsStream { io: PollEvented { io: Some(TcpStream { addr: 127.0.0.1:65397, peer: 127.0.0.1:8118, fd: 10 }) }, session: ClientSession { imp: ClientSessionImpl }, state: Stream }), certs: {}, state: Running, handshake_remaining: b"", proxy: Some(Proxy { socket: 127.0.0.1:8118, schema: Http }), protocols: [], extensions: [] }
thread 'tokio-runtime-worker' panicked at 'called `Result::unwrap()` on an `Err` value: HandShakeFailed("incomplete handshake response")', synchronizer/src/lib.rs:207:50
stack backtrace:

Payload size causes weird performance variance

image
as the snapshot shows, when using load_test code from example with different payload size, got a very strange performance variance. I don't know what causes it but I think a 10KB payload should be the real use case instead uWebsocket's load_test default 1MB payload size.

zmq like socket type support

the following socket types in zmq is very useful

  • pub/sub
  • push/pull
  • req/resp

should try to port them from zmq, but with easier monitor api

Help wanted: Create Node.js Bindings

Hi there, I am trying to create Node.js bindings for this library. Websockets are in high demand in Node.js & Javascript environments, so an npm package for this package would be really helpful.
Currently, uWebsockets is the fastest package in javascript environment, but this package can become a good competitor.

I tried to create bindings using napi-rs package template but got stuck with the Rust code. If the repo owner or someone knowledgable in Rust can help me, we can achieve this.

I managed to create a websocket connection using this and napi-rs but creating an API compatible with other websocket packages looks more challenging.

So, feel free to reply here or reach me at [email protected] if you want to help me.

None of the examples compile

I just cloned the repo for the first time and none of the examples compile. I see a bunch of things like unresolved import ws_tool::codec::WsBytesCodec. Can you re-clone your own repo and see whats going on?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.