From 18fa49322c3e5c909b84bca3a07b0985906e6a56 Mon Sep 17 00:00:00 2001 From: Firstminer Technology Date: Thu, 12 Feb 2026 18:26:18 +0530 Subject: [PATCH 1/5] gh-109532: fix socket HOWTO inaccuracy about send() on broken connection Correct the claim that send() returns 0 bytes on a broken connection. In practice, send() on a broken connection raises OSError (EPIPE) rather than returning 0. Only recv() returns 0 bytes to indicate disconnection. Add a clarifying comment to the mysend example noting this distinction. --- Doc/howto/sockets.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst index cbc49d15a0771b9..593705c999dbbb3 100644 --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -167,9 +167,10 @@ request, then reads a reply. That's it. The socket is discarded. This means tha a client can detect the end of the reply by receiving 0 bytes. But if you plan to reuse your socket for further transfers, you need to realize -that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* I repeat: if a socket -``send`` or ``recv`` returns after handling 0 bytes, the connection has been -broken. If the connection has *not* been broken, you may wait on a ``recv`` +that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* I repeat: if a +``recv`` returns 0 bytes, the connection has been broken. A ``send`` on a +broken connection will raise an :exc:`OSError` instead. If the connection has +*not* been broken, you may wait on a ``recv`` forever, because the socket will *not* tell you that there's nothing more to read (for now). Now if you think about that a bit, you'll come to realize a fundamental truth of sockets: *messages must either be fixed length* (yuck), *or @@ -201,6 +202,8 @@ length message:: sent = self.sock.send(msg[totalsent:]) if sent == 0: raise RuntimeError("socket connection broken") + # Note: in practice, send() on a broken connection + # raises OSError rather than returning 0. totalsent = totalsent + sent def myreceive(self): From 0cf09b41d05ba25bdcd95d450993c3eca179b37d Mon Sep 17 00:00:00 2001 From: Firstminer Technology Date: Thu, 19 Feb 2026 10:54:28 +0530 Subject: [PATCH 2/5] Address review: better emphasize send() vs recv() behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove informal 'I repeat:' phrasing. Restructure paragraph to clearly contrast recv() returning 0 bytes (a deliberate signal of disconnection) with send() raising OSError (an error condition — should never be called on a broken socket). Co-authored-by: bkap123 --- Doc/howto/sockets.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst index 593705c999dbbb3..eee375cf14534c0 100644 --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -167,10 +167,11 @@ request, then reads a reply. That's it. The socket is discarded. This means tha a client can detect the end of the reply by receiving 0 bytes. But if you plan to reuse your socket for further transfers, you need to realize -that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* I repeat: if a -``recv`` returns 0 bytes, the connection has been broken. A ``send`` on a -broken connection will raise an :exc:`OSError` instead. If the connection has -*not* been broken, you may wait on a ``recv`` +that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* If a ``recv`` +returns 0 bytes, the connection has been broken. In contrast, you should never +call ``send`` on a broken socket, as it will raise an :exc:`OSError` rather than +returning 0. If the connection has *not* been broken, you may wait on a +``recv`` forever, because the socket will *not* tell you that there's nothing more to read (for now). Now if you think about that a bit, you'll come to realize a fundamental truth of sockets: *messages must either be fixed length* (yuck), *or From c9f45c020facb426c653399e582da15e4220a0f3 Mon Sep 17 00:00:00 2001 From: Gh-Novel Date: Sat, 5 Sep 2026 06:51:47 +0530 Subject: [PATCH 3/5] gh-109532: rewrap paragraph in socket HOWTO --- Doc/howto/sockets.rst | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst index eee375cf14534c0..abdbe43c7c381af 100644 --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -171,13 +171,12 @@ that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* If a ``recv`` returns 0 bytes, the connection has been broken. In contrast, you should never call ``send`` on a broken socket, as it will raise an :exc:`OSError` rather than returning 0. If the connection has *not* been broken, you may wait on a -``recv`` -forever, because the socket will *not* tell you that there's nothing more to -read (for now). Now if you think about that a bit, you'll come to realize a -fundamental truth of sockets: *messages must either be fixed length* (yuck), *or -be delimited* (shrug), *or indicate how long they are* (much better), *or end by -shutting down the connection*. The choice is entirely yours, (but some ways are -righter than others). +``recv`` forever, because the socket will *not* tell you that there's nothing +more to read (for now). Now if you think about that a bit, you'll come to +realize a fundamental truth of sockets: *messages must either be fixed length* +(yuck), *or be delimited* (shrug), *or indicate how long they are* (much +better), *or end by shutting down the connection*. The choice is entirely +yours, (but some ways are righter than others). Assuming you don't want to end the connection, the simplest solution is a fixed length message:: From c0bb4bc0bd3bcf14c3e340e87d661aac9b19c21b Mon Sep 17 00:00:00 2001 From: Gh-Novel Date: Sat, 5 Sep 2026 07:06:16 +0530 Subject: [PATCH 4/5] gh-109532: drop redundant zero-length check from mysend example --- Doc/howto/sockets.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst index abdbe43c7c381af..3024ab749c11299 100644 --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -199,11 +199,9 @@ length message:: def mysend(self, msg): totalsent = 0 while totalsent < MSGLEN: + # No need to check for 0 here: send() raises OSError + # if the connection is broken. sent = self.sock.send(msg[totalsent:]) - if sent == 0: - raise RuntimeError("socket connection broken") - # Note: in practice, send() on a broken connection - # raises OSError rather than returning 0. totalsent = totalsent + sent def myreceive(self): From 235fdaad583ca7ac4b8bf037542ec39f20b90543 Mon Sep 17 00:00:00 2001 From: Gh-Novel Date: Sat, 5 Sep 2026 07:30:03 +0530 Subject: [PATCH 5/5] gh-109532: keep zero-length guard, soften OSError claim --- Doc/howto/sockets.rst | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Doc/howto/sockets.rst b/Doc/howto/sockets.rst index 3024ab749c11299..fa8f602f759fde4 100644 --- a/Doc/howto/sockets.rst +++ b/Doc/howto/sockets.rst @@ -169,13 +169,13 @@ a client can detect the end of the reply by receiving 0 bytes. But if you plan to reuse your socket for further transfers, you need to realize that *there is no* :abbr:`EOT (End of Transfer)` *on a socket.* If a ``recv`` returns 0 bytes, the connection has been broken. In contrast, you should never -call ``send`` on a broken socket, as it will raise an :exc:`OSError` rather than -returning 0. If the connection has *not* been broken, you may wait on a -``recv`` forever, because the socket will *not* tell you that there's nothing -more to read (for now). Now if you think about that a bit, you'll come to -realize a fundamental truth of sockets: *messages must either be fixed length* -(yuck), *or be delimited* (shrug), *or indicate how long they are* (much -better), *or end by shutting down the connection*. The choice is entirely +call ``send`` on a broken socket: rather than returning 0, it will normally +raise an :exc:`OSError`. If the connection has *not* been broken, you may +wait on a ``recv`` forever, because the socket will *not* tell you that there's +nothing more to read (for now). Now if you think about that a bit, you'll come +to realize a fundamental truth of sockets: *messages must either be fixed +length* (yuck), *or be delimited* (shrug), *or indicate how long they are* +(much better), *or end by shutting down the connection*. The choice is entirely yours, (but some ways are righter than others). Assuming you don't want to end the connection, the simplest solution is a fixed @@ -199,9 +199,12 @@ length message:: def mysend(self, msg): totalsent = 0 while totalsent < MSGLEN: - # No need to check for 0 here: send() raises OSError - # if the connection is broken. sent = self.sock.send(msg[totalsent:]) + if sent == 0: + # A broken connection almost always raises OSError + # from send(); a 0 return is rare, but guard against + # looping forever if it happens. + raise RuntimeError("socket connection broken") totalsent = totalsent + sent def myreceive(self):