一旦在套接字上使用O_NONBLOCK,有没有办法避免HUP?

时间:2015-12-06 02:05:38

标签: c linux sockets nonblocking

当我在阻塞模式下使用套接字时,我可以使用一个简单的系统来执行以下操作:

client            server

A -------------------> B
      register

A <------------------> B
   (various messages)

A -------------------> B
      unregister

在发送unregister消息之后,进程A可以立即退出,但B会按预期收到消息。

如果我打开A套接字上的非阻止模式,如果A发送该消息然后立即退出,则B永远不会收到unregister(我在发送{后通过添加sleep(1)进行测试{1}},在这种情况下,它按预期工作。)因此,或多或少,我的客户端无法干净地注销自己。

注意:当B unregister A套接字时,我收到一个Hanged Up信号(POLLHUP)而不是最后一条poll()信息,然后挂机。

我试图添加一个调用来重新打开阻止模式,但不知怎的,它没有任何区别。我使用以下代码更改阻止模式:

unregister

以防万一,我也尝试使用int optval(0 or 1); ioctl(get_socket(), FIONBIO, &optval); ,但我确信在内核方面调整相同的标记。

fcntl()

作为旁注,我使用int flags(fcntl(get_socket(), F_GETFL)); flags |= O_NONBLOCK; // use this line to turn ON flags &= ~O_NONBLOCK; // use this line to turn OFF fcntl(get_socket(), F_SETFL, flags); read()函数发送和接收我的消息。

更新

对于那些感兴趣的人,测试现在在我们的git中:

服务器:https://sourceforge.net/p/snapcpp/code/ci/master/tree/snapwebsites/tests/test_shutdown_server.cpp
客户:https://sourceforge.net/p/snapcpp/code/ci/master/tree/snapwebsites/tests/test_shutdown_client.cpp

这些使用快照库,主要是依赖于tcp客户端/服务器的snap_communicator:

tcp:https://sourceforge.net/p/snapcpp/code/ci/master/tree/snapwebsites/lib/tcp_client_server.cpp
沟通者:https://sourceforge.net/p/snapcpp/code/ci/master/tree/snapwebsites/lib/snap_communicator.cpp

2 个答案:

答案 0 :(得分:1)

正如您所发现的那样,套接字上的send仅对要发送的数据进行排队。它实际上并不意味着服务器得到它。这对于阻塞和非阻塞套接字都是如此。

几种可能性:

  1. 确保在客户端程序退出之前在套接字上调用close。如果发生这种情况,你没有在你的问题中说,但这可能是一个好主意。

  2. 如果#1不起作用,请使用套接字上的SO_LINGER选项。设置适当的超时间隔。

  3. 如下所示

      struct linger ling;
      ling.l_onoff = 1;
      ling.l_linger = 3; // 3 second wait for data to finish being set.
      setsockopt(s, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
    
    1. #2的替代方法是修改协议,以便客户端在关闭套接字并退出之前从服务器获取某种确认消息。或者为简单起见,客户端在退出之前等待服务器关闭套接字。 (当服务器关闭套接字时,recv将返回0)
    2. 我的建议是确保您已实施#1。如果这不适合你,请评估#3。 #2,如果没别的话。

答案 1 :(得分:1)

听起来你还没有在退出之前关闭套接字。在正常情况下,所有带SO_LINGER的恶作剧都不是必需的。