socket shutdown
如何优雅的关闭socket——shutdown()
背景
socket通信的应用那真是太多了。这次的项目是本地的多进程的通信。由于是windows进程通信中不支持msg,又不想把东西搞得太复杂,最后探讨的结果就是用socket进行连接通信。
由于没有明确的结束协议(因为内部有多线程的交流,到底谁是最后一个很难规定),所以在socket close之后,由于socket被占用,导致进程无法结束。从现象上看就是假死的感觉。(rcv哪里还是在接收的阻塞状态)
最初的解决案是自己发一个假的结束信号,socket内部的rcv接收到后,判断是否为结束信号。是的话退出rcv,但是发现不是每次都灵光。最后下定决心上网上找个优雅的解决方法。
shutdown
int shutdown(int sock, int howto); //Linux
int shutdown(SOCKET s, int howto); //Window
sock 为需要断开的套接字,howto 为断开方式。
howto 在 Linux 下有以下取值:
- SHUT_RD:断开输入流。套接字无法接收数据(即使输入缓冲区收到数据也被抹去),无法调用输入相关函数。
- SHUT_WR:断开输出流。套接字无法发送数据,但如果输出缓冲区中还有未传输的数据,则将传递到目标主机。
- SHUT_RDWR:同时断开 I/O 流。相当于分两次调用 shutdown(),其中一次以 SHUT_RD 为参数,另一次以 SHUT_WR 为参数。
howto 在 Windows 下有以下取值:
- SD_RECEIVE:关闭接收操作,也就是断开输入流。
- SD_SEND:关闭发送操作,也就是断开输出流。
- SD_BOTH:同时关闭接收和发送操作。
断开不意味着结束,资源也没有消失,所以正确的做法还应该继续close。
bool DbgSocketIf::disconnectSrv()
{
#if defined(__linux__)
shutdown(sClinet, SHUT_RDWR);
close(sClient);
#else
shutdown(sClinet, SD_BOTH);
closesocket(sClient);
WSACleanup();
#endif
return true;
}