python socket 超时设置 errno10054

本文介绍了如何解决使用Python读取网页时遇到的远程主机关闭连接的问题,包括设置socket超时时间、正确使用urlopen和urllib.request库,以及异常处理策略,确保程序稳定运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

python socket.error: [Errno 10054] 远程主机强迫关闭了一个现有的连接。问题解决方案:

前几天使用python读取网页。因为对一个网站大量的使用urlopen操作,所以会被那个网站认定为攻击行为。有时就不再允许下载。导致urlopen()后,request.read()一直卡死在那里。最后会抛出errno 10054.

这 个错误是connection reset by peer.也就是传说的远端主机重置了此连接。原因可能是socket超时时间过长;也可能是request = urllib.request.urlopen(url)之后,没有进行request.close()操作;也可能是没有sleep几秒,导致网站认定 这种行为是攻击。

具体解决方案如下面的代码:

view plaincopy to clipboardprint?
import socket  
import time  
timeout = 20    
socket.setdefaulttimeout(timeout)#这里对整个socket层设置超时时间。后续文件中如果再使用到socket,不必再设置  
sleep_download_time = 10 
time.sleep(sleep_download_time) #这里时间自己设定  
request = urllib.request.urlopen(url)#这里是要读取内容的url  
content = request.read()#读取,一般会在这里报异常  
request.close()#记得要关闭 
import socket
import time
timeout = 20 
socket.setdefaulttimeout(timeout)#这里对整个socket层设置超时时间。后续文件中如果再使用到socket,不必再设置
sleep_download_time = 10
time.sleep(sleep_download_time) #这里时间自己设定
request = urllib.request.urlopen(url)#这里是要读取内容的url
content = request.read()#读取,一般会在这里报异常
request.close()#记得要关闭

因为urlopen之后的read()操作其实是调用了socket层的某些函数。所以设置socket缺省超时时间,就可以让网络自己断掉。不必在read()处一直等待。

当然你也可以再外层再写几个try,except,例如:

view plaincopy to clipboardprint?
try:  
    time.sleep(self.sleep_download_time)  
    request = urllib.request.urlopen(url)  
    content = request.read()  
    request.close()  
      
except UnicodeDecodeError as e:  
         
    print('-----UnicodeDecodeErrorurl:',url)  
      
except urllib.error.URLError as e:  
    print("-----urlErrorurl:",url)  
 
except socket.timeout as e:  
    print("-----socket timout:",url) 
        try:
            time.sleep(self.sleep_download_time)
            request = urllib.request.urlopen(url)
            content = request.read()
            request.close()
           
        except UnicodeDecodeError as e:
              
            print('-----UnicodeDecodeErrorurl:',url)
           
        except urllib.error.URLError as e:
            print("-----urlErrorurl:",url)
  
        except socket.timeout as e:
            print("-----socket timout:",url)

一 般来说就莫有问题了。我测试了几千个网页的下载,然后才说出此话。不过如果是下载成千上万的,我做了下测试,ms还是会跳出这个异常。可能是 time.sleep()的时间太短,也可能是网络突然中断。我使用urllib.request.retrieve()测试了一下,发现不停的下载数 据,总会有失败的情况出现。

简单的处理方法是:首先参照的我的文章:python检查点简单实现 。先做一个检查点。然后将以上会跑出异常的那段代码while True一下。参见下面的伪代码:

view plaincopy to clipboardprint?
def Download_auto(downloadlist,fun,sleep_time=15):  
    while True:          
        try: # 外包一层try   
            value = fun(downloadlist,sleep_time) # 这里的fun是你的下载函数,我当函数指针传进来。 
           # 只有正常执行方能退出。  
            if value == Util.SUCCESS:  
                break 
        except : # 如果发生了10054或者IOError或者XXXError  
            sleep_time += 5 #多睡5秒,重新执行以上的download.因为做了检查点的缘故,上面的程序会从抛出异常的地方继续执行。防止了因为网络连接不稳定带来的程序中断。  
            print('enlarge sleep time:',sleep_time) 
def Download_auto(downloadlist,fun,sleep_time=15):
    while True:       
        try: # 外包一层try
            value = fun(downloadlist,sleep_time) # 这里的fun是你的下载函数,我当函数指针传进来。
           # 只有正常执行方能退出。
            if value == Util.SUCCESS:
                break
        except : # 如果发生了10054或者IOError或者XXXError
            sleep_time += 5 #多睡5秒,重新执行以上的download.因为做了检查点的缘故,上面的程序会从抛出异常的地方继续执行。防止了因为网络连接不稳定带来的程序中断。
            print('enlarge sleep time:',sleep_time)

不过对于找不到相应的网页,又要做另外的一番处理:

view plaincopy to clipboardprint?
# 打印下载信息  
def reporthook(blocks_read, block_size, total_size):  
    if not blocks_read:  
        print ('Connection opened')  
    if total_size < 0:  
        print ('Read %d blocks' % blocks_read)  
    else: 
        # 如果找不到,页面不存在,可能totalsize就是0,不能计算百分比  
        print('downloading:%d MB, totalsize:%d MB' % (blocks_read*block_size/1048576.0,total_size/1048576.0))  
        
 
def Download(path,url): 
#url = 'http://downloads.sourceforge.net/sourceforge/alliancep2p/Alliance-v1.0.6.jar' 
    #filename = url.rsplit("/")[-1]  
    try: 
    # python自带的下载函数  
        urllib.request.urlretrieve(url, path, reporthook)  
    except IOError as e: # 如果找不到,好像会引发IOError。  
        print("download ",url,"\nerror:",e)  
    print("Done:%s\nCopy to:%s" %(url,path)) 
# 打印下载信息
def reporthook(blocks_read, block_size, total_size):
    if not blocks_read:
        print ('Connection opened')
    if total_size < 0:
        print ('Read %d blocks' % blocks_read)
    else:
        # 如果找不到,页面不存在,可能totalsize就是0,不能计算百分比
        print('downloading:%d MB, totalsize:%d MB' % (blocks_read*block_size/1048576.0,total_size/1048576.0))
     

def Download(path,url):
#url = 'http://downloads.sourceforge.net/sourceforge/alliancep2p/Alliance-v1.0.6.jar'
    #filename = url.rsplit("/")[-1]
    try:
    # python自带的下载函数
        urllib.request.urlretrieve(url, path, reporthook)
    except IOError as e: # 如果找不到,好像会引发IOError。
        print("download ",url,"\nerror:",e)
    print("Done:%s\nCopy to:%s" %(url,path))

如果大家还是遇到了问题...请再评论里注上其他解决方案。

转载于:https://www.cnblogs.com/mmix2009/p/3224954.html

<think>我们被要求使用中文回答,并且需要遵循严格的格式要求。用户的问题是关于在Python中设置脚本执行的超时时间。 根据引用[1]、[2]、[4]和[5],我们可以知道有几种方法可以设置超时时间: 1. 使用subprocess模块,并在其中设置超时(引用[1]和[4])。 2. 使用socket设置超时(引用[2]和[5]),但这里用户的问题是关于脚本执行的超时,所以更可能是执行外部命令或函数。 用户的问题没有明确是执行外部命令还是内部函数,但根据引用,我们主要看到两种场景: - 执行外部命令或脚本(使用subprocess) - 执行网络请求(如SSE连接,引用[3])或系统时间设置(引用[2]和[5]) 由于问题比较宽泛,我将分别讨论两种常见情况:执行外部命令和内部代码块的超时。 ### 情况1:执行外部命令或脚本 使用`subprocess`模块,我们可以设置超时时间,并在超时后终止进程。 引用[1]和[4]提供了使用subprocess的例子,其中引用[4]提到“python通过subprocess模块调用系统命令。实际使用中,有一次是命令进入了交互模式,结果web端直接卡死了。调用时设置一个超时时间,时间用完后自动断开。” 在Python 3.3及以上版本,`subprocess.run`有一个`timeout`参数,可以设置超时时间。如果超时,会抛出`subprocess.TimeoutExpired`异常。 示例代码: ```python import subprocess try: # 设置超时时间为10秒 result = subprocess.run(['your_command', 'arg1', 'arg2'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=10) print(result.stdout.decode()) except subprocess.TimeoutExpired: print("命令执行超时!") ``` 对于更复杂的控制(如引用[1]中的例子),我们可以使用`subprocess.Popen`并配合轮询和超时机制。 ### 情况2:执行内部代码块(函数)的超时 如果我们需要对一段Python代码(函数)设置超时,可以使用信号(signal)或多线程/多进程。但注意,信号方法在Windows上可能不可用,而且主线程中使用信号可能会影响整个程序。 另一种方法是使用多进程,因为终止一个子进程比终止一个线程更安全。 使用`multiprocessing`模块的例子: ```python import multiprocessing import time def your_function(): # 模拟长时间运行的任务 time.sleep(20) return "完成" if __name__ == '__main__': pool = multiprocessing.Pool(processes=1) result = pool.apply_async(your_function) try: # 设置超时时间为10秒 output = result.get(timeout=10) print(output) except multiprocessing.TimeoutError: print("函数执行超时!") pool.terminate() # 终止进程池 pool.join() ``` 另外,也可以使用第三方库如`func_timeout`,它提供了更简单的超时控制。 ### 其他情况:网络请求等 对于网络请求,通常使用的库(如requests)有内置的超时参数。例如: ```python import requests try: response = requests.get('http://example.com', timeout=5) # 5秒超时 print(response.text) except requests.exceptions.Timeout: print("请求超时") ``` 对于SSE连接(引用[3]),我们可以通过设置底层的socket超时或使用带有超时控制的SSE客户端。 ### 总结 根据不同的场景,设置超时的方法不同: 1. 执行外部命令:使用`subprocess`模块的`timeout`参数。 2. 执行内部函数:使用多进程和`get`方法的`timeout`参数,或者使用第三方库。 3. 网络请求:使用相应库的超时参数。 现在,根据要求,我们需要生成相关问题。 §§相关问题§§ 1. 如何在Windows上设置Python函数的执行超时? 2. 使用subprocess设置超时后,如何获取超时前已经输出的内容? 3. 除了subprocess和multiprocessing,还有哪些方法可以设置超时? 4. 如何处理超时后资源的清理工作?</think>### Python设置脚本执行超时时间的方法 在Python中设置脚本执行的超时时间,主要有以下几种方法: #### 1. 使用subprocess模块(推荐) ```python import subprocess try: # 设置10秒超时 result = subprocess.run( ['python', 'your_script.py'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=10 # 超时时间(秒) ) print("输出:", result.stdout.decode()) except subprocess.TimeoutExpired: print("执行超时! 已终止进程") ``` #### 2. 使用signal模块(仅限Unix系统) ```python import signal import sys def handler(signum, frame): print("执行超时!") sys.exit(1) # 设置5秒超时 signal.signal(signal.SIGALRM, handler) signal.alarm(5) # 你的代码 try: # 需监控的代码块 time.sleep(10) # 模拟耗时操作 finally: signal.alarm(0) # 取消定时器 ``` #### 3. 使用多线程/进程(跨平台) ```python from multiprocessing import Pool import time def run_script(): # 需执行的函数 time.sleep(20) return "完成" if __name__ == '__main__': with Pool(processes=1) as pool: result = pool.apply_async(run_script) try: output = result.get(timeout=10) # 10秒超时 print(output) except TimeoutError: print("执行超时! 终止中...") pool.terminate() ``` #### 4. 使用装饰器(函数级超时) ```python import functools import errno import os import signal class TimeoutError(Exception): pass def timeout(seconds=10): def decorator(func): def wrapper(*args, **kwargs): def handler(signum, frame): raise TimeoutError("函数执行超时") signal.signal(signal.SIGALRM, handler) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return wrapper return decorator @timeout(5) def long_running_task(): time.sleep(10) return "完成" ``` ### 关键注意事项 1. **外部命令**:执行外部脚本建议使用`subprocess`,它能自动处理子进程终止[^4] 2. **资源清理**:超时后务必终止相关进程/线程,避免资源泄漏 3. **Windows限制**:`signal`模块在Windows上功能有限,建议使用`multiprocessing` 4. **精度问题**:超时控制精度通常在毫秒级,不能保证精确到微秒 5. **异常处理**:超时后应妥善处理中断状态和清理资源 > 对于网络请求超时,建议直接使用库的内置参数(如`requests.get(timeout=5)`),而非进程级控制[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值