客户报告了我无法理解的错误。基于TCP的客户端连接到从中接收数据的服务器,很少发送任何内容。通常一切都很好,但一旦在蓝色的月亮,就会发生这种情况:
以下是如何建立tcp连接(剥离所有日志,返回检查等)
ret = inet_pton(AF_INET, conn->address, &addr.sin_addr);
addr.sin_port = htons(conn->port); /* Server port */
addr.sin_family = AF_INET;
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(sock, (struct sockaddr *) &addr, sizeof(addr));
这是阅读包装器:
int32_t _readn ( int fd, uint8_t *vptr, int32_t n )
{
int32_t nleft;
int32_t nread;
uint8_t* ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ((nread = read (fd, ptr, nleft)) < 0) {
if (errno == EINTR) {
nread = 0;
} else {
return E_NETWORK_ERROR;
}
} else if ( nread == 0 ) {
break;
}
nleft -= nread;
ptr += nread;
}
return (n-nleft);
}
即使在连接关闭后,是否可以永久阻止读取调用?
我的包装中是否存在某种棘手的错误,我没注意到这可能会导致这种情况?我应该在连接时为套接字设置一些标志吗?
答案 0 :(得分:4)
问题的根源是如果没有数据要读取将阻止读取。例如。如果写入的字节少于预期的n个字节。这被称为阻塞读取。
要发现是否有数据,请使用select
作为Jite说。
最后,您可能会有防火墙丢弃实时连接。一些防火墙被配置为切断已经打开超过给定时间的连接,例如, 30分钟。可能这不是你所拥有的。
答案 1 :(得分:2)
我最终使用基于选择的函数来检查数据是否可用。
虽然神秘数据丢失背后的原因仍然未知(没有服务器错误被证实),但这似乎可以解决问题:
int32_t isReadDataAvailableOnSocket ( int sock, uint32_t waitTimeUs )
{
fd_set fds;
int16_t ret = 0;
struct timeval timeout;
struct timeval* timeoutPtr = NULL;
if (waitTimeUs>0) {
timeout.tv_sec = waitTimeUs / 1000000;
timeout.tv_usec = waitTimeUs % 1000000;
timeoutPtr = &timeout;
}
FD_ZERO ( &fds );
FD_SET ( sock, &fds );
ret = select ( sock+1, &fds, NULL, NULL, timeoutPtr );
if (ret == -1) {
WARN("select failed for udp socket=[%d]", sock);
return E_NETWORK_ERROR;
}
if ( ! FD_ISSET(sock, &fds) )
{
return E_NO_DATA;
}
else
{
return 0;
}
}