hgoldfish / qtnetworkng

QtNetwork Next Generation. A coroutine based network framework for Qt/C++, with more simpler API than boost::asio.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

将sslsocket设置为非阻塞模式不起作用

liuxiandeng opened this issue · comments

我将sslsocket设置为非阻塞模式不起作用

代码如下:

qtng::Socket::SocketOption option;
QVariant value(qtng::Socket::NonBlockingSocketOption);
pSslSocket->setOption(option, value);

请大佬有空的时候帮忙看看是不是用法不对

recv的时候,依旧阻塞在那里,由此确定设置为非阻塞模式没有起作用

qtng 是基于协程的,目的是在单个线程里面处理多个 socket 和 sslsocket,因此,所有的 socket 和 sslsocket 实际上都工作在非阻塞模式下,只是 API 看起来像是阻塞的。或许你需要理解一下协程的使用。

换一种说法,qtng 没有非阻塞模式,因为不需要。

In English: QtNetworkNg is coroutine-based. nonblocking mode is not need. We create QtNetworkNg because we hate nonblocking callbacks. If you want to handle many socket or sslsocket, you should spawn new coroutines, which handle one socket per coroutine.

你可以说一下你打算做什么,或许我能提供示例代码。

作者您好 我使用的场景是:客户端向服务器请求某种类型的数据,服务器收到请求后,开始向客户端一帧一帧的发送数据(总的数据量还挺大,几个G),客户端在接收数据的同时可能会请求服务器停止发送数据,因此我当时希望有非阻塞模式,服务端在一个循环里面每发送一帧数据,就去读一下,是否有“停止发送”的请求,没有“停止发送”的请求就接着发送数据。

我目前采用策略是,服务端对于每一个连接的接收、发送各开一个协程,但是又遇到了新的问题,当有好几个客户端(5个客户端)同时向服务器请求不同类型的数据,服务端开协程给不同客户端发送不同类型的数据时,有些发送数据的协程经常被执行,有些则很少被执行,我希望每个协程都能正常的被调度到,这样客户端各自请求的数据都能被正常接收到。(注:服务端对于每一个连接的接收、发送的协程里面msleep的时间都是一样的,但是不同类型的数据一帧的数据量是不一样的)

客户端代码比较简单先不说。服务端的话,发送与接收协程之间可以使用 qtng 的协程间通讯工具,主要有Lock, Semaphore, Event, Queue等等。比如这里,可以考虑使用Event. 当接收线程接收到要求暂停发送的数据包时,就把canSending这个Event 置为clear(),发送协程就会停止发送。接收到要求继续发送的数据包时,发送协程就继续发送。等待的时间要记得扣掉 canSending->wait() 的等待时间。

class MyServer
{
public:
    MyServer();
    ~MyServer();
    void serveForever();
private:
    CoroutineGroup *operations;
};


MyServer::MyServer()
    : operations(new CoroutineGroup()) {}

MyServer::~MyServer() { delete operations; }

void MyServer::serveForever()
{
    Socket s();
    s.bind(HostAddress::AnyIPv4, 8080);
    s.listen();
    while (true) {
        QSharedPointer<Socket> req(s.accept());
        if (req.isNull()) {
            break;
        }
        QSharedPointer<Event> canSending(new Event());
        canSending.set();
        //sending coroutine
        operations->spawn([canSending, req] {
            QElapsedTimer timer;
            while (true) {
                timer.restart(); 
                canSending->wait();
                if (!timer.hasExpired(200)) {   // send a packet every 200ms.
                    msleep(200 - timer.elasped());
                    canSending->wait();
                }
                const QByteArray &packet = makePackett();
                qint32 bs = req->sendall(packet);
                if (bs != packet.size()) {
                    qDebug("failed to send.");
                    req->close();
                    return;
                }
            }
        });
        // receiving coroutine
        operations->spawn([canSending, req]{
            while (true) {
                const QByteArray &packet = req.recv(1);
                if (packet.isEmpty()) {
                    qDebug("connectioned closed or may be some error occured.");
                    return;
                } else if (packet == "1") {  // to resume
                    canSending->set();
                } else {  // to pause
                    canSending->clear();
                }
            }
        });
    }
}

有些协程发送数据包时间长,有些时间短的话,最好不要简单用msleep(200)这种粗暴的写法,而是根据QElaspedTimer或者QDeadlineTimer计算更适合的等待时间。这两个类型都是 Qt 提供的工具,具体怎么用,可以看一下 Qt 的文档。或许会对你有用。

注意使用QDeadlineTimer的话,要求 Qt 5.8 以后。但可能这是更适合你这个场景的工具。

谢谢作者大佬的耐心回复和指导哈,我来重新实现一下我的代码,最近刚好人不舒服,才登录进来

谢谢作者 我的问题,在作者的帮助下都完美解决了 现在我把这个issue关闭了