C语言 关闭与关闭套接字?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4160347/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
close vs shutdown socket?
提问by
In C, I understood that if we close a socket, it means the socket will be destroyed and can be re-used later.
在 C 中,我理解如果我们关闭一个套接字,则意味着该套接字将被销毁并且可以在以后重新使用。
How about shutdown? The description said it closes half of a duplex connection to that socket. But will that socket be destroyed like closesystem call?
关机怎么办?描述说它关闭了与该套接字的双工连接的一半。但是那个套接字会像close系统调用一样被销毁吗?
采纳答案by Matthew Flaschen
This is explainedin Beej's networking guide. shutdownis a flexible way to block communication in one or both directions. When the second parameter is SHUT_RDWR, it will block both sending and receiving (like close). However, closeis the way to actually destroy a socket.
Beej 的网络指南对此进行了解释。 shutdown是一种灵活的方式来阻止一个或两个方向的通信。当第二个参数为 时SHUT_RDWR,它将阻止发送和接收(如close)。但是,close实际上是销毁套接字的方法。
With shutdown, you will still be able to receive pending data the peer already sent (thanks to Joey Adams for noting this).
使用shutdown,您仍然可以接收对等方已经发送的待处理数据(感谢 Joey Adams 注意到这一点)。
回答by Earth Engine
None of the existing answers tell people how shutdownand closeworks at the TCP protocol level, so it is worth to add this.
现有的答案都不告诉人们怎样shutdown和close工作在TCP协议层,所以它是值得添加此。
A standard TCP connection gets terminated by 4-way finalization:
标准 TCP 连接被 4 路终结终止:
- Once a participant has no more data to send, it sends a FIN packet to the other
- The other party returns an ACK for the FIN.
- When the other party also finished data transfer, it sends another FIN packet
- The initial participant returns an ACK and finalizes transfer.
- 一旦参与者没有更多的数据要发送,它就会向另一个参与者发送一个 FIN 数据包
- 对方对FIN返回ACK。
- 当对方也完成数据传输时,发送另一个FIN包
- 初始参与者返回 ACK 并完成传输。
However, there is another "emergent" way to close a TCP connection:
但是,还有另一种“紧急”方式可以关闭 TCP 连接:
- A participant sends an RST packet and abandons the connection
- The other side receives an RST and then abandon the connection as well
- 参与者发送 RST 数据包并放弃连接
- 另一端收到 RST 然后也放弃连接
In my test with Wireshark, with default socket options, shutdownsends a FIN packet to the other end but it is all it does. Until the other party send you the FIN packet you are still able to receive data. Once this happened, your Receivewill get an 0 size result. So if you are the first one to shut down "send", you should close the socket once you finished receiving data.
在我使用 Wireshark 进行的测试中,使用默认套接字选项,shutdown向另一端发送一个 FIN 数据包,但仅此而已。在对方向您发送 FIN 数据包之前,您仍然可以接收数据。一旦发生这种情况,您Receive将获得 0 尺寸的结果。因此,如果您是第一个关闭“发送”的人,则应在完成接收数据后关闭套接字。
On the other hand, if you call closewhilst the connection is still active (the other side is still active and you may have unsent data in the system buffer as well), an RST packet will be sent to the other side. This is good for errors. For example, if you think the other party provided wrong data or it refused to provide data (DOS attack?), you can close the socket straight away.
另一方面,如果您close在连接仍处于活动状态时调用(另一侧仍然处于活动状态,并且您可能在系统缓冲区中也有未发送的数据),则会向另一侧发送 RST 数据包。这对错误有好处。例如,如果您认为对方提供了错误的数据或拒绝提供数据(DOS 攻击?),您可以立即关闭套接字。
My opinion of rules would be:
我对规则的看法是:
- Consider
shutdownbeforeclosewhen possible - If you finished receiving (0 size data received) before you decided to shutdown, close the connection after the last send (if any) finished.
- If you want to close the connection normally, shutdown the connection (with SHUT_WR, and if you don't care about receiving data after this point, with SHUT_RD as well), and wait until you receive a 0 size data, and then close the socket.
- In any case, if any other error occurred (timeout for example), simply close the socket.
- 可能的话
shutdown先考虑close - 如果您在决定关闭之前完成接收(接收到 0 大小的数据),请在最后一次发送(如果有)完成后关闭连接。
- 如果想正常关闭连接,就关闭连接(用SHUT_WR,如果以后不关心接收数据,用SHUT_RD也是一样),等到收到0大小的数据,再关闭插座。
- 在任何情况下,如果发生任何其他错误(例如超时),只需关闭套接字即可。
Ideal implementations for SHUT_RD and SHUT_WR
SHUT_RD 和 SHUT_WR 的理想实现
The following haven't been tested, trust at your own risk. However, I believe this is a reasonable and practical way of doing things.
以下内容未经测试,请自行承担风险。但是,我相信这是一种合理且实用的做事方式。
If the TCP stack receives a shutdown with SHUT_RD only, it shall mark this connection as no more data expected. Any pending and subsequent readrequests (regardless whichever thread they are in) will then returned with zero sized result. However, the connection is still active and usable -- you can still receive OOB data, for example. Also, the OS will drop any data it receives for this connection. But that is all, no packages will be sent to the other side.
如果 TCP 堆栈接收到仅带有 SHUT_RD 的关闭,它将将此连接标记为没有更多的数据。任何未决和后续read请求(无论它们在哪个线程中)都将返回零大小的结果。但是,连接仍然处于活动状态并且可用——例如,您仍然可以接收 OOB 数据。此外,操作系统将丢弃它为此连接接收的任何数据。但这就是全部,不会将任何包裹发送到另一方。
If the TCP stack receives a shutdown with SHUT_WR only, it shall mark this connection as no more data can be sent. All pending write requests will be finished, but subsequent write requests will fail. Furthermore, a FIN packet will be sent to another side to inform them we don't have more data to send.
如果 TCP 堆栈接收到仅带有 SHUT_WR 的关闭,它应将此连接标记为不能发送更多数据。所有挂起的写请求都将完成,但后续的写请求将失败。此外,一个 FIN 数据包将被发送到另一端,以通知他们我们没有更多的数据要发送。
回答by Milan
There are some limitations with close()that can be avoided if one uses shutdown()instead.
close()如果使用它,则可以避免一些限制shutdown()。
close()will terminate both directions on a TCP connection. Sometimes you want to tell the other endpoint that you are finished with sending data, but still want to receive data.
close()将终止 TCP 连接上的两个方向。有时您想告诉另一个端点您已完成发送数据,但仍想接收数据。
close()decrements the descriptors reference count (maintained in file table entry and counts number of descriptors currently open that are referring to a file/socket) and does not close the socket/file if the descriptor is not 0. This means that if you are forking, the cleanup happens only after reference count drops to 0. With shutdown()one can initiate normal TCP close sequence ignoring the reference count.
close()递减描述符引用计数(在文件表条目中维护并计算当前打开的引用文件/套接字的描述符的数量)并且如果描述符不为 0,则不关闭套接字/文件。这意味着如果您正在分叉,只有在引用计数下降到 0 后才会进行清理。shutdown()可以启动正常的 TCP 关闭序列而忽略引用计数。
Parameters are as follows:
参数如下:
int shutdown(int s, int how); // s is socket descriptor
int howcan be:
int how可:
SHUT_RDor 0Further receives are disallowed
SHUT_RD或0不允许进一步接收
SHUT_WRor 1Further sends are disallowed
SHUT_WR或1不允许进一步发送
SHUT_RDWRor 2Further sends and receives are disallowed
SHUT_RDWR或2不允许进一步发送和接收
回答by Len Holgate
This may be platform specific, I somehow doubt it, but anyway, the best explanation I've seen is here on this msdn pagewhere they explain about shutdown, linger options, socket closure and general connection termination sequences.
这可能是特定于平台的,我有点怀疑,但无论如何,我见过的最好的解释是在这个 msdn 页面上,他们解释了关闭、延迟选项、套接字关闭和一般连接终止序列。
In summary, use shutdown to send a shutdown sequence at the TCP level and use close to free up the resources used by the socket data structures in your process. If you haven't issued an explicit shutdown sequence by the time you call close then one is initiated for you.
总之,使用 shutdown 在 TCP 级别发送关闭序列并使用 close 释放进程中套接字数据结构使用的资源。如果您在调用 close 时还没有发出明确的关闭序列,则会为您启动一个。
回答by Toby
I've also had success under linux using shutdown()from one pthread to force another pthread currently blocked in connect()to abort early.
我也在 linux 下使用shutdown()from 一个 pthread 强制当前阻塞的另一个 pthreadconnect()提前中止取得了成功。
Under other OSes (OSX at least), I found calling close()was enough to get connect()fail.
在其他操作系统(至少是 OSX)下,我发现调用close()足以connect()失败。
回答by Toby
回答by Neha Agrawal
Close
关闭
When you have finished using a socket, you can simply close its file descriptor with close; If there is still data waiting to be transmitted over the connection, normally close tries to complete this transmission. You can control this behavior using the SO_LINGER socket option to specify a timeout period; see Socket Options.
当你使用完一个套接字后,你可以简单地用 close 关闭它的文件描述符;如果仍有数据等待通过连接传输,则通常关闭尝试完成此传输。您可以使用 SO_LINGER 套接字选项指定超时时间来控制此行为;请参阅套接字选项。
ShutDown
关掉
You can also shut down only reception or transmission on a connection by calling shutdown.
您还可以通过调用 shutdown 仅关闭连接上的接收或传输。
The shutdown function shuts down the connection of socket. Its argument how specifies what action to perform: 0 Stop receiving data for this socket. If further data arrives, reject it. 1 Stop trying to transmit data from this socket. Discard any data waiting to be sent. Stop looking for acknowledgement of data already sent; don't retransmit it if it is lost. 2 Stop both reception and transmission.
shutdown 函数关闭socket 的连接。它的参数如何指定要执行的操作: 0 停止接收此套接字的数据。如果有更多数据到达,则拒绝它。1 停止尝试从此套接字传输数据。丢弃任何等待发送的数据。停止寻找已发送数据的确认;如果丢失,请不要重新传输。2 停止接收和发送。
The return value is 0 on success and -1 on failure.
成功时返回值为 0,失败时返回值 -1。
回答by simpx
in my test.
在我的测试中。
closewill send fin packet and destroy fd immediately when socket is not shared with other processes
close当套接字未与其他进程共享时,将发送 fin 数据包并立即销毁 fd
shutdownSHUT_RD, process can still recv data from the socket, but recvwill return 0 if TCP buffer is empty.After peer send more data, recvwill return data again.
shutdownSHUT_RD,进程仍然可以从套接字接收数据,但recv如果 TCP 缓冲区为空,recv则返回0。对端发送更多数据后,将再次返回数据。
shutdownSHUT_WRwill send fin packet to indicate the Further sends are disallowed. the peer can recv data but it will recv 0 if its TCP buffer is empty
shutdownSHUT_WR将发送 fin 数据包以指示不允许进一步发送。对等方可以接收数据,但如果其 TCP 缓冲区为空,它将接收 0
shutdownSHUT_RDWR(equal to use both SHUT_RDand SHUT_WR) will send rst packet if peer send more data.
shutdownSHUT_RDWR(等于同时使用SHUT_RD和SHUT_WR)如果对端发送更多数据,将发送第一个数据包。

