2009-06-25 165 views
0

我已经实现了一个简单的套接字包装类。它包括一个无阻塞功能:加速非阻塞Unix套接字(C++)

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); 
} 

该类还包含一个简单的接收功能:

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

在实践中,似乎有一个〜15ms的延迟时插槽::的recv()是调用。这个延迟是否可以避免?我见过一些使用select()的非阻塞示例,但不明白这可能会有帮助。

回答

1

这取决于你如何使用套接字。如果您有多个套接字,并且您在所有这些套接字上循环检查可能导致延迟的数据。

对于非阻塞recv,您取决于存在的数据。如果您的应用程序需要使用多个套接字,则必须轮流连接每个套接字以查找其中是否有任何数据可用。

这对系统资源不利,因为这意味着即使没有任何事情可做,您的应用程序也会持续运行。

你可以通过select来避免这种情况。你基本上设置你的套接字,将它们添加到组中并在组上选择。当任何选定的套接字发生任何事情时,选择返回指定发生了什么以及在哪个套接字上。

有关如何使用select看看beej's guide to network programming

+0

谢谢你的建议,但我的问题认为字面上只有1个套接字,其中recv()的调用呈现不可接受的15毫秒延迟。既然它只是轮询1个套接字,我猜猜问题在别处是不正确的吗? – duckworthd 2009-06-25 03:23:04

+0

可能还有其他因素,根据少量代码无法判断发生了什么。如果只有一个套接字,并且我假设您正在等待数据,为什么您要使用非阻塞?这是否意味着您在等待数据时正在做其他事情?其他工作是否有可能让您一收到数据就马上收到数据? – stefanB 2009-06-25 03:37:05

0

选择会让你指定超时,并且可以测试插座已经可以读出一些代码。所以你可以使用小于15ms的东西。顺便提一句,如果线路上的数据可以包含嵌入式NUL,则不必包含所有读取的数据,您需要注意您拥有的代码。你应该使用类似s.assign(buffer, status);

0

除了stefanB,我发现你每次都清零你的缓冲区。何必? recv返回实际读取的字节数。 (缓冲区[状态+ 1] = NULL后只需将一个字节清零)

0

MAXRECV有多大?这可能就是因为堆栈增长而导致页面错误。其他人已经提到,清零接收缓冲区是完全没有必要的。当您从收到的字符数据中创建std::string时,您还可以进行内存分配和复制匹配。