Python TCP 断开连接检测

11

我有一个简单的TCP示例:

import socket
import time


TCP_IP = '127.0.0.1'
TCP_PORT = 81
BUFFER_SIZE = 1024

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))

while True:
    s.send(bytes('hello', 'UTF-8'))
    time.sleep(1)

s.close()

我如何检测到与服务器的连接已经中断,以及如何安全地重新连接?

是否有必要等待服务器的回复?

更新:

import socket
import time

TCP_IP = '127.0.0.1'
TCP_PORT = 81
BUFFER_SIZE = 1024

def reconnect():
    toBreak = False
    while True:
        s.close()
        try:
            s.connect((TCP_IP, TCP_PORT))
            toBreak = True
        except:
            print ("except")        
        if toBreak:
            break
        time.sleep(1)


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))

while True:
    try:    
        s.send(bytes('hello', 'UTF-8'))
        print ("sent hello")
    except socket.error as e:
        reconnect()

    time.sleep(1)

s.close()
如果我中断连接,会出现一个错误(不太重要),然后重新连接。但是在恢复连接后,连接会返回以下错误:
OSError: [WinError 10038] 尝试对非套接字进行操作
如果我重新启动调用相同的 s.connect((TCP_IP, TCP_PORT)) 的脚本,它可以正常工作。
4个回答

10

如果连接已经丢失或断开,您将收到一个 socket.error[Errno 104] Connection reset by peer 异常(也称为 ECONNRESET),在调用 send()recv() 时。因此,要检测它,只需捕获该异常:

while True:
    try:
        s.send(bytes('hello', 'UTF-8'))
    except socket.error, e:
        if e.errno == errno.ECONNRESET:
            # Handle disconnection -- close & reopen socket etc.
        else:
            # Other error, re-raise
            raise
    time.sleep(1)

你是不是想说:除了 socket.error as e: ?如果我终止连接,它会引发以下错误:ECONNABORTED,但重新连接不起作用。 - András Kovács
@AndrásKovács:as,都是将异常对象存储到目标变量的相同语法。如果您看到的是ECONNABORTED而不是ECONNRESET,那么也要测试该值并适当处理它。一旦套接字达到错误状态,就无法重用该套接字。您必须关闭套接字并打开一个新的套接字。 - Adam Rosenfield
更新了帖子。看起来,简单的重新连接并不能解决问题。 - András Kovács
或者,你可以使用 except ConnectionResetError: - Generic Ratzlaugh

4

尝试重新连接时,请使用一个新的套接字。

def connect():
    while True:
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((host, port))
            return s.makefile('w')
        except socket.error as e:
            log("socket error {} reconnecting".format(e))
            time.sleep(5)

dest = connect()
while True:
    line = p.stdout.readline()
    try:
        dest.write(line)
        dest.flush()
    except socket.error as e:
        log("socket error {} reconnecting".format(e))
        dest = connect()

这将打开无限数量的袜子。在打开新的之前,您应该关闭它们。 - Caah Arch
@CaahArch 不,它不会打开无限数量的套接字。它只打开一个并返回它。之前失败的那个套接字,即抛出socket.error的那个,当s变量超出作用域时会自动关闭。Python变量作用域规则适用。 - jrwren

0

你能试试这个吗(我觉得你没有尝试过socket.SO_REUSEADDR):

def open_connection():
    data0=''

    try:
        # Create a TCP/IP socket
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        # Connect the socket to the port where the server is listening
        server_address = ('192.168.0.100', 8000)
        sock.settimeout(10)     # TimeOut 5 secunde

        while True:

            try:
                sock.connect(server_address)
                message = 'new connection'
                sock.sendall(message)

                # Look for the response
                amount_received = 0
                data0=sock.recv(1024)
                amount_received = len(data0)
                return

            finally:
                wNET = 0
                pass

    except:
        sock.close()
        time.sleep(60)
        del data0

0

这是基于线程的代码。主要提示是,如果套接字已连接,则接收缓冲区不能为空。

import time
import socket
import threading

def connect():
    while True:
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((host, port))
            s.settimeout(60)
            return s
        except socket.error as e:
            print("socket error {} reconnecting".format(e))
            time.sleep(5)

soc = connect()

def runSocket():
    global soc
    while True:
        try:
            recBuf = soc.recv(64)
            if recBuf == b'':    #remote server disconnect
                soc = connect()
            else:
                print(recBuf)
        except socket.timeout:
            print("Timeout")
        except Exception as e:
            print("other socket error {}".format(e))
            soc = connect()

socketThread = threading.Thread(target=runSocket)
socketThread.start()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接