python tcp连接状态判断_套接字-如何判断python中的连接是否中断

套接字-如何判断python中的连接是否中断

我希望我的python应用程序能够知道另一侧的套接字何时被删除。 有办法吗?

5个解决方案

44 votes

简短回答:

使用非阻塞的recv()或阻塞的recv()/ select()   超时时间短。

答案很长:

处理套接字连接的方法是根据需要进行读取或写入,并准备处理连接错误。

TCP区分“丢弃”连接的3种形式:超时,重置,关闭。

其中,无法真正检测到超时,TCP可能只会告诉您时间尚未到期。 但是,即使它告诉您,时间可能仍会在此之后过期。

还要记住,您或您的对等方(连接的另一端)都使用shutdown()可能仅关闭传入的字节流,并使传出的字节流保持运行,或者关闭传出的字节流,并使传入的流保持运行。

因此严格来说,您想检查读取流是否已关闭,或者写入流是否已关闭,或者两者均已关闭。

即使连接“断开”,您仍然应该能够读取仍在网络缓冲区中的任何数据。 只有在缓冲区为空后,您才会收到与recv()的断开连接。

检查连接是否断开就像询问“读取当前缓冲的所有数据后我将收到什么?” 为了找出答案,您只需读取当前已缓冲的所有数据。

我可以看到“读取所有缓冲的数据”到底如何对某些人来说可能是个问题,他们仍然将recv()视为阻塞函数。 使用阻塞的recv()时,如果缓冲区已为空,则“检查”读取将被阻塞,这违背了“检查”的目的。

在我看来,任何被证明有可能无限期地阻塞整个过程的功能都是设计缺陷,但我想由于历史原因,它仍然存在,就像使用常规文件描述符一样,使用套接字是一个很不错的主意。

您可以做的是:

将套接字设置为非阻塞模式,但会收到系统相关的错误,以指示接收缓冲区为空或发送缓冲区已满

坚持阻塞模式,但设置非常短的套接字超时。 这将使您可以使用recv()“ ping”或“检查”套接字,几乎可以完成此操作

使用select()调用或异步模块,且超时时间非常短。 错误报告仍然是特定于系统的。

对于问题的写入部分,将读取缓冲区保持为空几乎可以解决这一问题。 在非阻塞的读取尝试之后,您会发现连接“断开”,并且您可以选择在读取返回关闭的通道后停止发送任何内容。

我想确保发送的数据已到达另一端(并且仍不在发送缓冲区中)的唯一方法是:

在同一套接字上收到对您发送的确切消息的正确响应。 基本上,您正在使用更高级别的协议来提供确认。

在套接字上执行成功的shutdown()和close()

python socket howto说send()如果关闭通道,将返回0个写入的字节。 您可以使用非阻塞或超时的socket.send(),如果它返回0,则无法再在该套接字上发送数据。 但是,如果返回非零值,则说明您已经发送了一些东西,祝您好运:)

同样在这里,我没有考虑将OOB(带外)套接字数据用作解决问题的一种方法,但是我认为OOB并不是您的意思。

Toughy answered 2019-11-04T02:27:05Z

36 votes

这取决于您所说的“丢弃”。 对于TCP套接字,如果另一端通过以下方式关闭连接close()或进程终止,您将通过读取文件结尾或获取读取错误来查找,通常是操作系统将errno设置为“对等方重置的连接”。 对于python,您将读取长度为零的字符串,否则将导致套接字。尝试从套接字读取或写入时将引发错误。

answered 2019-11-04T02:24:30Z

14 votes

从Jweede发布的链接中:

异常socket.timeout:

This exception is raised when a timeout occurs on a socket

which has had timeouts enabled via a prior call to settimeout().

The accompanying value is a string whose value is currently

always “timed out”.

这是python文档中套接字模块的演示服务器和客户端程序

# Echo server program

import socket

HOST = '' # Symbolic name meaning all available interfaces

PORT = 50007 # Arbitrary non-privileged port

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind((HOST, PORT))

s.listen(1)

conn, addr = s.accept()

print 'Connected by', addr

while 1:

data = conn.recv(1024)

if not data: break

conn.send(data)

conn.close()

和客户:

# Echo client program

import socket

HOST = 'daring.cwi.nl' # The remote host

PORT = 50007 # The same port as used by the server

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect((HOST, PORT))

s.send('Hello, world')

data = s.recv(1024)

s.close()

print 'Received', repr(data)

在我从中提取的文档示例页面上,有更复杂的示例采用了这种想法,但这是简单的答案:

假设您正在编写客户端程序,只需将所有可能会丢失套接字的代码放入try块中...

try:

s.connect((HOST, PORT))

s.send("Hello, World!")

...

except socket.timeout:

# whatever you need to do when the connection is dropped

Jiaaro answered 2019-11-04T02:28:09Z

5 votes

我将此博客文章中的代码示例转换为Python:如何检测客户端何时关闭连接?它对我来说很有效:

from ctypes import (

CDLL, c_int, POINTER, Structure, c_void_p, c_size_t,

c_short, c_ssize_t, c_char, ARRAY

)

__all__ = 'is_remote_alive',

class pollfd(Structure):

_fields_ = (

('fd', c_int),

('events', c_short),

('revents', c_short),

)

MSG_DONTWAIT = 0x40

MSG_PEEK = 0x02

EPOLLIN = 0x001

EPOLLPRI = 0x002

EPOLLRDNORM = 0x040

libc = CDLL(None)

recv = libc.recv

recv.restype = c_ssize_t

recv.argtypes = c_int, c_void_p, c_size_t, c_int

poll = libc.poll

poll.restype = c_int

poll.argtypes = POINTER(pollfd), c_int, c_int

class IsRemoteAlive: # not needed, only for debugging

def __init__(self, alive, msg):

self.alive = alive

self.msg = msg

def __str__(self):

return self.msg

def __repr__(self):

return 'IsRemoteClosed(%r,%r)' % (self.alive, self.msg)

def __bool__(self):

return self.alive

def is_remote_alive(fd):

fileno = getattr(fd, 'fileno', None)

if fileno is not None:

if hasattr(fileno, '__call__'):

fd = fileno()

else:

fd = fileno

p = pollfd(fd=fd, events=EPOLLIN|EPOLLPRI|EPOLLRDNORM, revents=0)

result = poll(p, 1, 0)

if not result:

return IsRemoteAlive(True, 'empty')

buf = ARRAY(c_char, 1)()

result = recv(fd, buf, len(buf), MSG_DONTWAIT|MSG_PEEK)

if result > 0:

return IsRemoteAlive(True, 'readable')

elif result == 0:

return IsRemoteAlive(False, 'closed')

else:

return IsRemoteAlive(False, 'errored')

kay answered 2019-11-04T02:28:32Z

4 votes

如果我没记错的话,这通常是通过超时来处理的。

Jon W answered 2019-11-04T02:28:56Z

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值