bpo-32373: Add socket.getblocking() method. (#4926)
This commit is contained in:
parent
631fd38dbf
commit
f11b460d87
|
@ -1087,6 +1087,16 @@ to sockets.
|
||||||
to decode C structures encoded as byte strings).
|
to decode C structures encoded as byte strings).
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: socket.getblocking()
|
||||||
|
|
||||||
|
Return ``True`` if socket is in blocking mode, ``False`` if in
|
||||||
|
non-blocking.
|
||||||
|
|
||||||
|
This is equivalent to checking ``socket.gettimeout() == 0``.
|
||||||
|
|
||||||
|
.. versionadded:: 3.7
|
||||||
|
|
||||||
|
|
||||||
.. method:: socket.gettimeout()
|
.. method:: socket.gettimeout()
|
||||||
|
|
||||||
Return the timeout in seconds (float) associated with socket operations,
|
Return the timeout in seconds (float) associated with socket operations,
|
||||||
|
|
|
@ -98,6 +98,12 @@ def _have_socket_vsock():
|
||||||
ret = get_cid() is not None
|
ret = get_cid() is not None
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def _is_fd_in_blocking_mode(sock):
|
||||||
|
return not bool(
|
||||||
|
fcntl.fcntl(sock, fcntl.F_GETFL, os.O_NONBLOCK) & os.O_NONBLOCK)
|
||||||
|
|
||||||
|
|
||||||
HAVE_SOCKET_CAN = _have_socket_can()
|
HAVE_SOCKET_CAN = _have_socket_can()
|
||||||
|
|
||||||
HAVE_SOCKET_CAN_ISOTP = _have_socket_can_isotp()
|
HAVE_SOCKET_CAN_ISOTP = _have_socket_can_isotp()
|
||||||
|
@ -4079,8 +4085,44 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
|
||||||
# Testing whether set blocking works
|
# Testing whether set blocking works
|
||||||
self.serv.setblocking(True)
|
self.serv.setblocking(True)
|
||||||
self.assertIsNone(self.serv.gettimeout())
|
self.assertIsNone(self.serv.gettimeout())
|
||||||
|
self.assertTrue(self.serv.getblocking())
|
||||||
|
if fcntl:
|
||||||
|
self.assertTrue(_is_fd_in_blocking_mode(self.serv))
|
||||||
|
|
||||||
self.serv.setblocking(False)
|
self.serv.setblocking(False)
|
||||||
self.assertEqual(self.serv.gettimeout(), 0.0)
|
self.assertEqual(self.serv.gettimeout(), 0.0)
|
||||||
|
self.assertFalse(self.serv.getblocking())
|
||||||
|
if fcntl:
|
||||||
|
self.assertFalse(_is_fd_in_blocking_mode(self.serv))
|
||||||
|
|
||||||
|
self.serv.settimeout(None)
|
||||||
|
self.assertTrue(self.serv.getblocking())
|
||||||
|
if fcntl:
|
||||||
|
self.assertTrue(_is_fd_in_blocking_mode(self.serv))
|
||||||
|
|
||||||
|
self.serv.settimeout(0)
|
||||||
|
self.assertFalse(self.serv.getblocking())
|
||||||
|
self.assertEqual(self.serv.gettimeout(), 0)
|
||||||
|
if fcntl:
|
||||||
|
self.assertFalse(_is_fd_in_blocking_mode(self.serv))
|
||||||
|
|
||||||
|
self.serv.settimeout(10)
|
||||||
|
self.assertTrue(self.serv.getblocking())
|
||||||
|
self.assertEqual(self.serv.gettimeout(), 10)
|
||||||
|
if fcntl:
|
||||||
|
# When a Python socket has a non-zero timeout, it's
|
||||||
|
# switched internally to a non-blocking mode.
|
||||||
|
# Later, sock.sendall(), sock.recv(), and other socket
|
||||||
|
# operations use a `select()` call and handle EWOULDBLOCK/EGAIN
|
||||||
|
# on all socket operations. That's how timeouts are
|
||||||
|
# enforced.
|
||||||
|
self.assertFalse(_is_fd_in_blocking_mode(self.serv))
|
||||||
|
|
||||||
|
self.serv.settimeout(0)
|
||||||
|
self.assertFalse(self.serv.getblocking())
|
||||||
|
if fcntl:
|
||||||
|
self.assertFalse(_is_fd_in_blocking_mode(self.serv))
|
||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
try:
|
try:
|
||||||
self.serv.accept()
|
self.serv.accept()
|
||||||
|
@ -4113,6 +4155,8 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
|
||||||
self.serv.close()
|
self.serv.close()
|
||||||
self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM |
|
self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM |
|
||||||
socket.SOCK_NONBLOCK)
|
socket.SOCK_NONBLOCK)
|
||||||
|
self.assertFalse(self.serv.getblocking())
|
||||||
|
self.assertEqual(self.serv.gettimeout(), 0)
|
||||||
self.port = support.bind_port(self.serv)
|
self.port = support.bind_port(self.serv)
|
||||||
self.serv.listen()
|
self.serv.listen()
|
||||||
# actual testing
|
# actual testing
|
||||||
|
@ -5190,11 +5234,24 @@ class NonblockConstantTest(unittest.TestCase):
|
||||||
self.assertEqual(s.gettimeout(), timeout)
|
self.assertEqual(s.gettimeout(), timeout)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
fcntl.fcntl(s, fcntl.F_GETFL, os.O_NONBLOCK) & os.O_NONBLOCK)
|
fcntl.fcntl(s, fcntl.F_GETFL, os.O_NONBLOCK) & os.O_NONBLOCK)
|
||||||
|
if timeout == 0:
|
||||||
|
# timeout == 0: means that getblocking() must be False.
|
||||||
|
self.assertFalse(s.getblocking())
|
||||||
|
else:
|
||||||
|
# If timeout > 0, the socket will be in a "blocking" mode
|
||||||
|
# from the standpoint of the Python API. For Python socket
|
||||||
|
# object, "blocking" means that operations like 'sock.recv()'
|
||||||
|
# will block. Internally, file descriptors for
|
||||||
|
# "blocking" Python sockets *with timeouts* are in a
|
||||||
|
# *non-blocking* mode, and 'sock.recv()' uses 'select()'
|
||||||
|
# and handles EWOULDBLOCK/EAGAIN to enforce the timeout.
|
||||||
|
self.assertTrue(s.getblocking())
|
||||||
else:
|
else:
|
||||||
self.assertEqual(s.type, socket.SOCK_STREAM)
|
self.assertEqual(s.type, socket.SOCK_STREAM)
|
||||||
self.assertEqual(s.gettimeout(), None)
|
self.assertEqual(s.gettimeout(), None)
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
fcntl.fcntl(s, fcntl.F_GETFL, os.O_NONBLOCK) & os.O_NONBLOCK)
|
fcntl.fcntl(s, fcntl.F_GETFL, os.O_NONBLOCK) & os.O_NONBLOCK)
|
||||||
|
self.assertTrue(s.getblocking())
|
||||||
|
|
||||||
@support.requires_linux_version(2, 6, 28)
|
@support.requires_linux_version(2, 6, 28)
|
||||||
def test_SOCK_NONBLOCK(self):
|
def test_SOCK_NONBLOCK(self):
|
||||||
|
@ -5204,15 +5261,15 @@ class NonblockConstantTest(unittest.TestCase):
|
||||||
socket.SOCK_STREAM | socket.SOCK_NONBLOCK) as s:
|
socket.SOCK_STREAM | socket.SOCK_NONBLOCK) as s:
|
||||||
self.checkNonblock(s)
|
self.checkNonblock(s)
|
||||||
s.setblocking(1)
|
s.setblocking(1)
|
||||||
self.checkNonblock(s, False)
|
self.checkNonblock(s, nonblock=False)
|
||||||
s.setblocking(0)
|
s.setblocking(0)
|
||||||
self.checkNonblock(s)
|
self.checkNonblock(s)
|
||||||
s.settimeout(None)
|
s.settimeout(None)
|
||||||
self.checkNonblock(s, False)
|
self.checkNonblock(s, nonblock=False)
|
||||||
s.settimeout(2.0)
|
s.settimeout(2.0)
|
||||||
self.checkNonblock(s, timeout=2.0)
|
self.checkNonblock(s, timeout=2.0)
|
||||||
s.setblocking(1)
|
s.setblocking(1)
|
||||||
self.checkNonblock(s, False)
|
self.checkNonblock(s, nonblock=False)
|
||||||
# defaulttimeout
|
# defaulttimeout
|
||||||
t = socket.getdefaulttimeout()
|
t = socket.getdefaulttimeout()
|
||||||
socket.setdefaulttimeout(0.0)
|
socket.setdefaulttimeout(0.0)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add socket.getblocking() method.
|
|
@ -136,6 +136,7 @@ sendall(data[, flags]) -- send all data\n\
|
||||||
send(data[, flags]) -- send data, may not send all of it\n\
|
send(data[, flags]) -- send data, may not send all of it\n\
|
||||||
sendto(data[, flags], addr) -- send data to a given address\n\
|
sendto(data[, flags], addr) -- send data to a given address\n\
|
||||||
setblocking(0 | 1) -- set or clear the blocking I/O flag\n\
|
setblocking(0 | 1) -- set or clear the blocking I/O flag\n\
|
||||||
|
getblocking() -- return True if socket is blocking, False if non-blocking\n\
|
||||||
setsockopt(level, optname, value[, optlen]) -- set socket options\n\
|
setsockopt(level, optname, value[, optlen]) -- set socket options\n\
|
||||||
settimeout(None | float) -- set or clear the timeout\n\
|
settimeout(None | float) -- set or clear the timeout\n\
|
||||||
shutdown(how) -- shut down traffic in one or both directions\n\
|
shutdown(how) -- shut down traffic in one or both directions\n\
|
||||||
|
@ -2525,6 +2526,27 @@ Set the socket to blocking (flag is true) or non-blocking (false).\n\
|
||||||
setblocking(True) is equivalent to settimeout(None);\n\
|
setblocking(True) is equivalent to settimeout(None);\n\
|
||||||
setblocking(False) is equivalent to settimeout(0.0).");
|
setblocking(False) is equivalent to settimeout(0.0).");
|
||||||
|
|
||||||
|
/* s.getblocking() method.
|
||||||
|
Returns True if socket is in blocking mode,
|
||||||
|
False if it is in non-blocking mode.
|
||||||
|
*/
|
||||||
|
static PyObject *
|
||||||
|
sock_getblocking(PySocketSockObject *s)
|
||||||
|
{
|
||||||
|
if (s->sock_timeout) {
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(getblocking_doc,
|
||||||
|
"getblocking()\n\
|
||||||
|
\n\
|
||||||
|
Returns True if socket is in blocking mode, or False if it\n\
|
||||||
|
is in non-blocking mode.");
|
||||||
|
|
||||||
static int
|
static int
|
||||||
socket_parse_timeout(_PyTime_t *timeout, PyObject *timeout_obj)
|
socket_parse_timeout(_PyTime_t *timeout, PyObject *timeout_obj)
|
||||||
{
|
{
|
||||||
|
@ -2581,7 +2603,30 @@ sock_settimeout(PySocketSockObject *s, PyObject *arg)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
s->sock_timeout = timeout;
|
s->sock_timeout = timeout;
|
||||||
if (internal_setblocking(s, timeout < 0) == -1) {
|
|
||||||
|
int block = timeout < 0;
|
||||||
|
/* Blocking mode for a Python socket object means that operations
|
||||||
|
like :meth:`recv` or :meth:`sendall` will block the execution of
|
||||||
|
the current thread until they are complete or aborted with a
|
||||||
|
`socket.timeout` or `socket.error` errors. When timeout is `None`,
|
||||||
|
the underlying FD is in a blocking mode. When timeout is a positive
|
||||||
|
number, the FD is in a non-blocking mode, and socket ops are
|
||||||
|
implemented with a `select()` call.
|
||||||
|
|
||||||
|
When timeout is 0.0, the FD is in a non-blocking mode.
|
||||||
|
|
||||||
|
This table summarizes all states in which the socket object and
|
||||||
|
its underlying FD can be:
|
||||||
|
|
||||||
|
==================== ===================== ==============
|
||||||
|
`gettimeout()` `getblocking()` FD
|
||||||
|
==================== ===================== ==============
|
||||||
|
``None`` ``True`` blocking
|
||||||
|
``0.0`` ``False`` non-blocking
|
||||||
|
``> 0`` ``True`` non-blocking
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (internal_setblocking(s, block) == -1) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
@ -4601,6 +4646,8 @@ static PyMethodDef sock_methods[] = {
|
||||||
sendto_doc},
|
sendto_doc},
|
||||||
{"setblocking", (PyCFunction)sock_setblocking, METH_O,
|
{"setblocking", (PyCFunction)sock_setblocking, METH_O,
|
||||||
setblocking_doc},
|
setblocking_doc},
|
||||||
|
{"getblocking", (PyCFunction)sock_getblocking, METH_NOARGS,
|
||||||
|
getblocking_doc},
|
||||||
{"settimeout", (PyCFunction)sock_settimeout, METH_O,
|
{"settimeout", (PyCFunction)sock_settimeout, METH_O,
|
||||||
settimeout_doc},
|
settimeout_doc},
|
||||||
{"gettimeout", (PyCFunction)sock_gettimeout, METH_NOARGS,
|
{"gettimeout", (PyCFunction)sock_gettimeout, METH_NOARGS,
|
||||||
|
|
Loading…
Reference in New Issue