我负责通过TCP连接导出数据的服务器。对于服务器发送的每个数据记录,它要求客户端发回短的“\ n”确认消息。我有一位客户声称他发送的确认信息未从网络服务器上读取。以下是我在套接字上用于I / O的代码:
bool can_send = true;
char tx_buff[1024];
char rx_buff[1024];
struct pollfd poll_descriptor;
int rcd;
poll_descriptor.fd = socket_handle;
poll_descriptor.events = POLLIN | POLLOUT;
poll_descriptor.revents = 0;
while(!should_quit && is_connected)
{
// if we know that data can be written, we need to do this before we poll the OS for
// events. This will prevent the 100 msec latency that would otherwise occur
fill_write_buffer(write_buffer);
while(can_send && !should_quit && !write_buffer.empty())
{
uint4 tx_len = write_buffer.copy(tx_buff, sizeof(tx_buff));
rcd = ::send(
socket_handle,
tx_buff,
tx_len,
0);
if(rcd == -1 && errno != EINTR)
throw SocketException("socket write failure");
write_buffer.pop(rcd);
if(rcd > 0)
on_low_level_write(tx_buff, rcd);
if(rcd < tx_len)
can_send = false;
}
// we will use poll for up to 100 msec to determine whether the socket can be read or
// written
if(!can_send)
poll_descriptor.events = POLLIN | POLLOUT;
else
poll_descriptor.events = POLLIN;
poll(&poll_descriptor, 1, 100);
// check to see if an error has occurred
if((poll_descriptor.revents & POLLERR) != 0 ||
(poll_descriptor.revents & POLLHUP) != 0 ||
(poll_descriptor.revents & POLLNVAL) != 0)
throw SocketException("socket hung up or socket error");
// check to see if anything can be written
if((poll_descriptor.revents & POLLOUT) != 0)
can_send = true;
// check to see if anything can be read
if((poll_descriptor.revents & POLLIN) != 0)
{
ssize_t bytes_read;
ssize_t total_bytes_read = 0;
int bytes_remaining = 0;
do
{
bytes_read = ::recv(
socket_handle,
rx_buff,
sizeof(rx_buff),
0);
if(bytes_read > 0)
{
total_bytes_read += bytes_read;
on_low_level_read(rx_buff,bytes_read);
}
else if(bytes_read == -1)
throw SocketException("read failure");
ioctl(
socket_handle,
FIONREAD,
&bytes_remaining);
}
while(bytes_remaining != 0);
// recv() will return 0 if the socket has been closed
if(total_bytes_read > 0)
read_event::cpost(this);
else
{
is_connected = false;
closed_event::cpost(this);
}
}
}
我已经基于假设poll()是一个级别触发函数编写了这段代码,并且只要有来自套接字的数据就会立即解除阻塞。我读过的所有内容似乎都支持这个假设。有没有理由我可能错过了会导致上述代码错过读取事件的原因?
答案 0 :(得分:4)
它不是边缘触发的。它始终是水平触发的。我将不得不阅读您的代码来回答您的实际问题。但这回答了标题中的问题。 : - )
我在代码中看不出明确的原因,为什么您可能会看到您所看到的行为。但是你的问题的范围远远大于你提出的代码,我不能假装这是一个完整的问题诊断。
答案 1 :(得分:1)
根据您自己对问题的评估(也就是说,当您希望能够阅读确认时,您在poll
被阻止),那么您最终会超时。
如果客户的计算机距离您的服务器超过50毫秒,那么在收到确认之前您将始终超时连接,因为您只需等待100毫秒。这是因为数据到达客户至少需要50ms,而确认返回至少需要50ms。
答案 2 :(得分:1)
它是水平触发的。如果轮询时套接字接收缓冲区中有数据,则会触发POLLIN;如果套接字发送缓冲区中有空间(几乎总是存在),则POLLOUT将触发。