当我在阻塞模式下使用套接字时,我可以使用一个简单的系统来执行以下操作:
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
答案 0 :(得分:1)
正如您所发现的那样,套接字上的send
仅对要发送的数据进行排队。它实际上并不意味着服务器得到它。这对于阻塞和非阻塞套接字都是如此。
几种可能性:
确保在客户端程序退出之前在套接字上调用close
。如果发生这种情况,你没有在你的问题中说,但这可能是一个好主意。
如果#1不起作用,请使用套接字上的SO_LINGER
选项。设置适当的超时间隔。
如下所示
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));
recv
将返回0)我的建议是确保您已实施#1。如果这不适合你,请评估#3。 #2,如果没别的话。
答案 1 :(得分:1)
听起来你还没有在退出之前关闭套接字。在正常情况下,所有带SO_LINGER的恶作剧都不是必需的。