简体   繁体   English

加速非阻塞Unix套接字(C ++)

[英]Speeding up non-blocking Unix Sockets (C++)

I've implemented a simple socket wrapper class. 我实现了一个简单的套接字包装器类。 It includes a non-blocking function: 它包括一个非阻塞功能:

void Socket::set_non_blocking(const bool b) {
    mNonBlocking = b; // class member for reference elsewhere
    int opts = fcntl(m_sock, F_GETFL);
    if(opts < 0) return;
    if(b)
        opts |= O_NONBLOCK;
    else
        opts &= ~O_NONBLOCK;

    fcntl(m_sock, F_SETFL, opts);
}

The class also contains a simple receive function: 该类还包含一个简单的接收函数:

int Socket::recv(std::string& s) const {
    char buffer[MAXRECV + 1];
    s = "";
    memset(buffer,0,MAXRECV+1);
    int status = ::recv(m_sock, buffer, MAXRECV,0);

    if(status == -1) {
    if(!mNonBlocking)
        std::cout << "Socket, error receiving data\n";

        return 0;
    } else if (status == 0) {
        return 0;
    } else {
        s = buffer;
        return status;
    }
}

In practice, there seems to be a ~15ms delay when Socket::recv() is called. 在实践中,调用Socket :: recv()似乎会有约15ms的延迟。 Is this delay avoidable? 可以避免这种延迟吗? I've seen some non-blocking examples that use select(), but don't understand how that might help. 我已经看到了一些使用select()的非阻塞示例,但不了解这可能有什么帮助。

It depends on how you using sockets. 这取决于您如何使用套接字。 If you have multiple sockets and you loop over all of them checking for data that may account for the delay. 如果您有多个套接字,并且遍历所有套接字,请检查可能导致延迟的数据。

With non-blocking recv you are depending on data being there. 使用非阻塞接收,您将取决于那里的数据。 If your application need to use more than one socket you will have to constantly pool each socket in turns to find out if any of them have data available. 如果您的应用程序需要使用多个套接字,则必须不断地逐个池化每个套接字,以找出其中是否有可用数据。

This is bad for system resources because it means your application is constantly running even when there is nothing to do. 这对系统资源不利,因为这意味着即使无事可做,您的应用程序仍在不断运行。

You can avoid that with select. 您可以通过选择来避免这种情况。 You basically set up your sockets, add them to group and select on the group. 基本上,您要设置套接字,将其添加到组中并在组中选择。 When anything happens on any of the selected sockets select returns specifying what happened and on which socket. 在任何选定的套接字上发生任何事情时,select返回指定发生了什么以及在哪个套接字上。

For some code about how to use select look at beej's guide to network programming 有关select 用法的一些代码,请参见beej的网络编程指南。

select will let you a specify a timeout, and can test if the socket is ready to be read from. select将让您指定一个超时,并可以测试套接字是否已准备好从中读取。 So you can use something smaller than 15ms. 因此,您可以使用小于15ms的内容。 Incidentally you need to be careful with that code you have, if the data on the wire can contain embedded NULs s won't contain all the read data. 顺便说一句,如果线路上的数据可以包含嵌入式NUL,则不会包含所有读取的数据,因此您需要小心使用已有的代码。 You should use something like s.assign(buffer, status); 您应该使用类似s.assign(buffer, status);东西s.assign(buffer, status); .

In addition to stefanB, I see that you are zeroing out your buffer every time. 除了stefanB,我看到您每次都将缓冲区清零。 Why bother? 何必呢? recv returns how many bytes were actually read. recv返回实际读取的字节数。 Just zero out the one byte after ( buffer[status+1]=NULL ) 后面的一个字节只是零(buffer [status + 1] = NULL)

How big is your MAXRECV ? 您的MAXRECV It might just be that you incur a page fault on the stack growth. 可能只是由于堆栈增长而导致页面错误。 Others already mentioned that zeroing out the receive buffer is completely unnecessary. 其他人已经提到,将接收缓冲区清零是完全没有必要的。 You also take memory allocation and copy hit when you create a std::string out of received character data. 当您从接收到的字符数据中创建std::string时,还需要进行内存分配和复制命中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM