Giter Site home page Giter Site logo

ironsdu / brynet Goto Github PK

View Code? Open in Web Editor NEW
1.0K 69.0 241.0 2.07 MB

A Header-Only cross-platform C++ TCP network library . We can use vcpkg(https://github.com/Microsoft/vcpkg/tree/master/ports/brynet) install brynet.

License: MIT License

C 10.82% C++ 88.87% CMake 0.31%
cross-platform networking tcp-library multithreading c-plus-plus http https websocket cpp11 header-only

brynet's Introduction

Brynet

Header Only Cross platform high performance TCP network library using C++ 11.

996.icu LICENSE Platform

Build status

build-and-test

Features

  • Header only
  • Cross platform (Linux | Windows | MacOS)
  • High performance and safety use.
  • None depend
  • Multi-threaded
  • SSL support
  • Support HTTP、HTTPS、WebSocket
  • IPv6 support

Documentation

Compatibility

  • Visual C++ 2013+ (32/64-bit)
  • GCC 4.8+ (32/64-bit)
  • Clang (Supported C++ 11)

Macro

  • BRYNET_VERSION
  • BRYNET_USE_OPENSSL

Build Example

  1. cmake . -Dbrynet_BUILD_EXAMPLES=ON -Dbrynet_BUILD_TESTS=ON
  2. If you use Windows, please open brynet.sln then build. If on Linux or MacOS, only enter make.

Only Install

  1. cmake .
  2. sudo make install

Usages

Benchmark

Under localhost, use CentOS 6.5 virtual mahcine(host machine is Win10 i5)

  • PingPong

    Benchamrk's server and client both only use one thread, and packet size is 4k

    PingPong

  • Broadcast

    Server use two network threads and one logic thread, client use one network(also process logic) thread. every packet size is 46 bytes. every packet contain client's id. server broadcast packet to all client when recv one packet from any client. client send one packet when recv packet from server and packet's id equal self.

    Broadcast

  • Ab HTTP(1 network thread)

    Server Hostname:        127.0.0.1
    Server Port:            9999
  
    Document Path:          /abc/de?a=1
    Document Length:        25 bytes
    
    Concurrency Level:      100
    Time taken for tests:   17.734 seconds
    Complete requests:      500000
    Failed requests:        0
    Total transferred:      41000000 bytes
    HTML transferred:       12500000 bytes
    Requests per second:    28194.36 [#/sec] (mean)
    Time per request:       3.547 [ms] (mean)
    Time per request:       0.035 [ms] (mean, across all concurrent requests)
    Transfer rate:          2257.75 [Kbytes/sec] received
    
    Connection Times (ms)
    min  mean[+/-sd] median   max
    Connect:        0    2   0.2      2       3
    Processing:     1    2   0.3      2       7
    Waiting:        0    1   0.4      1       6
    Total:          2    4   0.2      4       7
    
    Percentage of the requests served within a certain time (ms)
    50%      4
    66%      4
    75%      4
    80%      4
    90%      4
    95%      4
    98%      4
    99%      4
    100%      7 (longest request)

Examples

Users

brynet's People

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  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

brynet's Issues

有100个客户端给100个服务端发送数据,send函数没有发送成功,没有进入send的callback

image

大神好,我们这边有这样一个场景,我这边维护了100个客户端的tcp长连接,每隔5s就会给服务端发送心跳数据,期间可能会有ftp大数据量的发送,我正在给100个客户端使用curl发送300M的视频的时候,tcp的send函数没有进入回调,意味数据着没有投递出去,但是我们的应用程序还正在运行,也没有其他异常,下图中我看您的代码中有这样的注释,不知道是否何其有关?
image

希望可以支持header-only

因越来越多的库支持header-only以方便用户直接使用,而无需编译,所以建议可以支持head-only。

具体可以再讨论。

Buffer filling up quickly / how to end connections

Hey,

this is kind of a follow up to my last request #70 as I went further with my implementation. As I got a stable sample running I integrated the code into another project to have the image transfer inside an application. Currently I have a class managing the image transmission in a thread where other modules of the software deliver an image defined as in the sample https://gist.github.com/irieger/74808b0db67c39e33d37641e210e26bc. The image transmission currently is done in by first creating a connectionBuilder and then sending the data if an image is in the queue:

    brynet::net::wrapper::ConnectionBuilder connectionBuilder;
    connectionBuilder.configureService(service)
        .configureConnector(connector)
        .configureConnectionOptions({
            brynet::net::AddSocketOption::AddEnterCallback(enterCallback),
            brynet::net::AddSocketOption::WithMaxRecvBufferSize(m_network_buffer_megabytes * 1024 * 1024)
        });

    bool has_data = false;
    while (m_running)
    {
        {
            std::lock_guard<std::mutex> lock(m_queue_mtx);
            has_data = (m_queue.size() > 0);
        }
        if (has_data)
        {
            try
            {
                connectionBuilder.configureConnectOptions({
                        brynet::net::ConnectOption::WithAddr(m_target_ip, m_target_port),
                        brynet::net::ConnectOption::WithTimeout(std::chrono::seconds(1)),
                        brynet::net::ConnectOption::WithFailedCallback(failedCallback),
                        brynet::net::ConnectOption::AddProcessTcpSocketCallback([](brynet::net::TcpSocket& socket) {
                            socket.setNodelay();
                        })
                    })
                    .asyncConnect();
            }
            catch (std::runtime_error& e)
            {
                std::cerr << "[ImageTransmitter]  error:" << e.what() << std::endl;
            }
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(3));
    }

This might not be the ideal solution but worked in my first tests. Today I did some longer experiments and realized my memory usage on the receiver side increased steadily until I ran into errors. As I found out the memory was only freed after closing the sender, thus it seems something isn't freed unless the client connection is stopped. Is this correct? When is the receiver freeing the memory? I expected that after returning the size of processed bytes in the DataCallback the memory would be reused.

The other point is, I now have a number of open connections blocking resources besides the memory usage. Can I automatically close after the send is done? I send with code like this to ensure the data is removed from RAM after the sent (this is the enter callback):

    auto enterCallback = [this](const brynet::net::TcpConnection::Ptr& session)
    {
        session->setDataCallback([session, this](const char* buffer, size_t len)
        {
            return len;  // No answer is currently expected so should be irrelevant.
        });
        // while (m_running)  // uncommented in alternative route (see below)
        {
            // ... code pulling the next image data/size pair from an std::queue
            // ... fills the following variables:
            char* data;
            size_t data_size;

            // sending the actual data
            session->send(data, data_size, [data]()
                {
                    std::free(data);
                });
            // std::this_thread::sleep_for(std::chrono::milliseconds(10));  // sleep in the alternative case to slow queue/lock checking
        }

After the free I'd also like to close the session now but there seems to be no close/disconnect whatever method in this class.

Btw. the brynet::net::ConnectOption::WithTimeout(std::chrono::seconds(1)) only means a timeout in case the connection can't be established, not an overall timeout, right?

Alternative route

I tried an alternative route creating one or two sender connections waiting for new data in the queue and sending it. Besides a while(m_running) around the block pulling data from the queue and sending it nothing is changed but I don't reach the send callback anymore. This is with or without an additional mutex blocking as long as send is executed (mutex.lock() before the send and mutex.unlock() in the send callback after the free.

With the std::cout debug output of the size send data (after the call) I see the sender passed the send call, but the send-Callback isn't reached and neither is the debugging output on the server side showing the DataCallback being called.
Any hint on this?

I could take the time to rewrite the example code to fully show the data flow if needed for understanding what I did.

hope the examples is simple

希望可以examples里面加一点简单点的例子, 例如普通的Client和Server, 原谅我例子里面一个都没看懂... 我只是个小白 希望有一点简单的client server例子即可 感谢 👍

考虑支持FTP吗

如果把FTP支持上,当然如果能再封装一下UDP,那么基础的网络算是支持全了,期待

Problems sending larger data junks - data splitted on receive

Hey, I stumbled past brynet a few times and thought that I should give it a try. I'm doing a small proof of concept simple binary data send/receive in the local network (image transfer for displaying on another machine). As I want to keep dependencies low and prefer not to depend on a big codebase as boost, brynet catched my eye. The base was easy to understand with the sample PingPongClient/Server and my adaptation looked good. However there is one showstopper for me:

Data fragmentation

(Modified sample code used here: https://gist.github.com/irieger/74808b0db67c39e33d37641e210e26bc)

Without finding a documentation I expected the send/receive code to abstract the fragmentation and split/combine data into the fragments needed for network transfer. For example sending an image with 1920x1080 pixels with RGBA (4 channels) of float32 data the image has already 33177600 bytes. Or in the sample code 1920*1080 with 3 channels of uint16_t 74649600 bytes. Therefore I set WithMaxRecvBufferSize(1535 * 1024 * 1024); and just send the data in the client. The data consist of a simple header (format[int32_t], height[uint32_t], width[uint32_t]) + the image data, thus in my sample 33177612 bytes. (Sample code above adapted as the actual code is inside another project, but the sample code shows the effect)

This data is now received via three calls of my callback (set with setDataCallback). My test code (interpreting the first 12 bytes as the header so any data there is expected to represent my format, height and width) results in a correct expected size for the first junk and invalid expected sizes afterwards instead of one received package. Combined the size is correct:

Received image smaller than described by header
     Expected: 33177612, got: 65482
Received image smaller than described by header
     Expected: 3044704916, got: 65482
Received image smaller than described by header
     Expected: 4185915404, got: 33046648

Three calls to the callback seem to be reproducible when only one transfer happens. When sending two images in parallel the callback is executed a varying number of times, some samples are 387 or 403 times. However using a different buffer size like 512 MB the number of packets differs.

Is there an integrated way to send/receive larger binary junks reliable at once or would some boilerplate be needed to split and receive in junks below a certain limit? Where is the limit or how would one need to modify the examples for larger datasets?

How to get a list of opened sessions ?

Hi,
I'd like to send messages from the server to every client connected (using websocket). I don't see how to do that. I was expecting to find a list with all the sessions opened.

there is a way to send messages to each client from the server (using websocket) ?

thx

循环get请求 间隔1毫秒 就会出这个问题

/brynet/net/http/http_parser.h:1604: size_t http_parser_execute(http_parser*, const http_parser_settings*, const char*, size_t): assertion "HTTP_PARSER_ERRNO(parser) == HPE_OK" failed
Segmentation fault

Does this work with Android/iOS?

Hi, I'm planning to build a cross-platform program which must work in windows, linux, macOS, android and iOS.

Does brynet works with all of these platforms? (of course, in android, for example, using the NDK + JNI).

If it isn't, which libraries are using brynet that are incompatible?

Regards,
Knife.

怎么保证send数据成功了呢?

我看send函数里面有个回调函数,但是没有返回参数,因此只能知道send发送完成了,但是不能知道send有没有发送到缓冲区?

ssl 开启后不work

tcp+ssl的使用。 我在windows/linux下使用有问题,发现 'mOpenSSLCTX = SSL_CTX_new(SSLv23_method())' 初始处理指针为空,也没见调用‘SSL_library_init’的地方,是否测试过呢?

how can I get cookies sent by clients ?

from,

auto httpEnterCallback = [&port](const HTTPParser& httpParser,
            const HttpSession::Ptr& session) {
...
});

I try to access cookies, however I haven' t found any method for that.

In the meantime I have seen that HttpRequest has setCookie, I would excpect a symetrical method getCookie somewhere I can access when I receive a request from a client.

HttpClient无法执行

httpserver是可以的,我用postman发包能收到,但是httpclient执行失败,我只修改了Host(改成我目标主机的IP:port),WithAddr修改为我运行httpclient主机的IP,端口依然80,报错 connect failed,请问这个需要改其他地方吗?谢谢

例子中的广播报文服务端收不到,请问如何设置IP地址?

网络状态:
IP:192.168.0.17
掩码:192.168.252.0
网关192.168.0.1

计算后的广播地址:192.168.3.255
命令行调用如下:BroadCaseServer.exe 9999
BroadCaseClient.exe 192.168.3.255 9999 100 100
在同一台计算机上,报文可以发送出去,但服务端程序没有收到。

BroadCaseClient.exe 192.168.0.17 9999 100 100 可以收到回应。

mac下cmake修改

不想提交PR了,mac下cmakelist这里修改下,这样编译出来的libbrynet.dylib的install name为
@rpath/libbrynet.dylib (compatibility version 0.0.0, current version 0.0.0)
相当于gcc下的-Wl -rpath=xxx

if(APPLE)
  set(CMAKE_MACOSX_RPATH 0)
endif()

修改为

if(APPLE)
  set(CMAKE_MACOSX_RPATH 1)
endif()

Feauture Request: Add REUSEPORT and REUSEADDR

This feature allows us to run multiple instance of the same App running on a single port.
I have this I'm using in my code in /brynet/net/SocketLibFunction.hpp

  static int  SocketSetReusePort(BrynetSocketFD fd)
  {
     int enable = 1;
     return ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &enable, sizeof(enable));
  }

The issue now is where to put it. I currently call this function in brynet/net/SocketLibFunction.hpp in ``

        const auto socketfd = isIPV6 ?
            socket(AF_INET6, SOCK_STREAM, 0) :
            socket(AF_INET, SOCK_STREAM, 0);
        if (socketfd == BRYNET_INVALID_SOCKET)
        {
            return BRYNET_INVALID_SOCKET;
        }

        SocketSetReusePort(socketfd);
...

I tried adding:

        void             setReusePort(bool yes = true)
        {
            if (yes)
            {
               brynet::net::base::SocketSetReusePort(mFD);
            }
        }

to Socket.hpp, it seems nothing in

.configureSocketOptions({
                [&](TcpSocket& socket) {
                    socket.setReuseAddr(true);
                    socket.setReusePort(true);
                    socket.setNodelay();
            },
        })

ever gets called.

some file miss

brynet\utils\coroutine.c(216): fatal error C1083: 无法打开包括文件: “brynet/utils/stack.h”: No such file or directory

httpclient等待消息时长问题

httpclient文件中等到消息是下述方式,需要人为触发,
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
if (brynet::base::app_kbhit())
{
break;
}
}
我改成std::this_thread::sleep_for(std::chrono::seconds(1));方式依然不能满足我的要求,因为时长的设定值不好确定,而且设定太大浪费时间,设定太小的话很可能等不到消息,改成同步的话应该可以,但是改的代码太多了,请问有没有自动触发的机制啊?谢谢

主分支没源代码?

master分支只有头文件,没有源代码文件呢?其他分支倒是有,不知道是否是最新的

请教个问题,详见内文

我使用httpclient携带一个参数,发送http请求到后端,处理正常,携带3个参数,发生异常,新加的两个参数格式为“年 月-日 时-分-秒”,打印出来requestStr看结果,符合预期,能够抓到发出的http请求包,和响应包,响应包为400 badRequest,但是我在setHttpCallback设置的打印未生效,但是使用打印出的requestStr码流,使用postman构造后发出,却能正确处理,请教两个问题:
1、我使用了asyncConnect启动发送请求操作,也使用了while循环保证退出,但是抓包看到400响应,但是为什么设置的回调未成功?
2、发出的http请求码流编码有什么特殊处理吗?我根据打印的码流借助postman发出去,却能正确处理?

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.