我实现了一个简单的套接字包装类。它包括一个非阻塞函数:
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;
}
}
实际上,调用Socket :: recv()时似乎有~15ms的延迟。这种延迟是否可以避免?我已经看到一些使用select()的非阻塞示例,但不明白这可能会有什么帮助。
答案 0 :(得分:1)
这取决于你如何使用套接字。如果您有多个套接字并且遍历所有套接字,则检查可能导致延迟的数据。
使用非阻塞recv,你取决于那里的数据。如果您的应用程序需要使用多个套接字,则必须不断地轮流汇集每个套接字以查明是否有任何数据可用。
这对系统资源不利,因为这意味着即使无事可做,您的应用程序也会持续运行。
你可以用select来避免这种情况。您基本上设置了套接字,将它们添加到组并在组上进行选择。当任何选定套接字上发生任何事情时,select返回指定发生了什么以及在哪个套接字上。
有关如何使用select beej's guide to network programming
的一些代码答案 1 :(得分:0)
select将允许您指定超时,并可以测试套接字是否可以读取。所以你可以使用小于15ms的东西。顺便提一下,如果线上的数据可能包含嵌入的NUL,则需要小心使用该代码,否则将不包含所有读取的数据。您应该使用类似s.assign(buffer, status);
的内容。
答案 2 :(得分:0)
除了stefanB之外,我发现你每次都在调整你的缓冲区。何必? recv返回实际读取的字节数。只需将(缓冲区[status + 1] = NULL)
后的一个字节清零答案 3 :(得分:0)
你的MAXRECV
有多大?可能只是因为您在堆栈增长时出现页面错误。其他人已经提到将接收缓冲区归零是完全没必要的。当您从收到的字符数据中创建std::string
时,您还可以进行内存分配和复制命中。