2013-07-31 20 views
2

我有一个简单的tcp/ip服务器用C++在linux上编写。我使用异步套接字和epoll。当我收到EPOLLIN事件时,是否有可能找出有多少字节可供阅读?我怎样才能获得可用于在Linux上的异步套接字上读取的字节数?

+0

为什么? recv()会告诉你,并给你数据。 – EJP

+0

那么,有时知道缓冲区的大小可能相当方便,应该将其分配给阅读。例如,在kqueue中,字节数在数据字段中返回。 –

+0

恕我直言,你不应该分配一个缓冲区来阅读。这只会产生垃圾,堆碎片等。您应该使用本地分配的字节数组。 – EJP

回答

7

man 7 tcp

int value; 
error = ioctl(sock, FIONREAD, &value); 

或替代地SIOCINQ,这是FIONREAD的同义词。

无论如何,我建议只是在循环中以非阻塞模式使用recv,直到它返回EWOULDBLOCK

UPDATE:

从您的评论下面我想,这是不是你的问题,相应的解决方案。

想象一下,你的标题是8字节,你只收到4;那么你的poll/select将返回EPOLLIN,你会检查FIONREAD,看到头还没有完成和更多的字节wayt。但是这些字节永远不会到达,因此每次调用poll/select时都会收到EPOLLIN,并且您有一个无操作的忙循环。也就是说,poll/select级触发的。不是边缘触发功能也可以解决您的问题。

最后,你做得好一点,每个连接添加一个缓冲区,然后排队字节,直到有足够的空间。它并不像看起来那么困难,而且效果更好。例如,类似的东西:

struct ConnectionData 
{ 
    int sck; 
    std::vector<uint8_t> buffer; 
    size_t offset, pending; 
}; 

void OnPollIn(ConnectionData *d) 
{ 
    int res = recv(d->sck, d->buffer.data() + offset, d->pending); 
    if (res < 0) 
     handle_error(); 
    d->offset += res; 
    d->pending -= res; 

    if (d->pending == 0) 
     DoSomethingUseful(d); 
} 

,只要你想得到的字节数:

void PrepareToRecv(ConnectionData *d, size_t size) 
{ 
    d->buffer.resize(size); 
    d->offset = 0; 
    d->pending = size; 
} 
+0

谢谢你的回答!是的,我可以使用recv或像这样读取,但我有一个二进制协议,它将数据包的大小存储在它的头中,所以我认为代码可以变得更简单,如果我要检查头是否已经可以读取或不。 –

+0

@PavelDavydov:事实上,在这里有一个缓冲区和积累可能(只是)有点复杂。但我认为你可能会削减太多的角落......请看我的更新。 – rodrigo

+0

是的,无休止地获取EPOLLIN可能是一个问题,谢谢。我的服务器的行为方式与您推荐的类似,我只是认为它可以做得更简单,更清洁。 –

相关问题