Python多线程递增写入文件及端口扫描丢行问题求解
问题解答
1. 多线程向单个文件递增写入数字的实现
多线程写入同一文件的核心是避免竞态条件(多个线程同时写文件导致内容覆盖、乱序),可以通过threading.Lock线程锁保证同一时间只有一个线程操作文件。
示例代码:
import threading # 创建全局锁,控制文件写入权限 file_lock = threading.Lock() def write_number(num): # 自动获取/释放锁,确保写入操作独占 with file_lock: with open("numbers.txt", "a", encoding="utf-8") as f: f.write(f"{num}\n") def main(): threads = [] # 启动100个线程,分别写入1-100 for i in range(1, 101): t = threading.Thread(target=write_number, args=(i,)) threads.append(t) t.start() # 等待所有线程执行完毕 for t in threads: t.join() if __name__ == "__main__": main()
2. 多线程端口扫描记录不全的问题解决
需求可行性
完全可行,问题出在你代码中的几个关键bug,导致部分端口未被扫描或记录。
代码问题分析
- 代码1的致命问题:
- 异常处理中使用
sys.exit():单个线程触发socket.timeout或socket.gaierror时,会直接终止整个进程,导致后续未执行的线程全部停止,这是记录数不足的核心原因。 - 设置了守护线程(
t.daemon = True):若主进程提前结束,未完成的守护线程会被强制终止,导致任务中断。
- 异常处理中使用
- 代码2的致命问题:
- 子线程数量计算错误:
number_of_sub_threads = port - final_port会得到负数,导致range(port, port + number_of_sub_threads)循环无法执行,漏掉最后一批端口。
- 子线程数量计算错误:
正确实现方案
以下是修复后的完整代码,确保1000个端口全部被扫描并记录:
import socket import threading import sys # 文件写入锁,避免多线程写入冲突 file_lock = threading.Lock() def check_port(ip_host, port): try: my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) my_socket.settimeout(5) result = my_socket.connect_ex((ip_host, port)) # 加锁写入,保证文件操作安全 with file_lock: with open("./ports.txt", "a+", encoding="utf-8") as f: if result == 0: f.write(f"Port {port} is open.\n") else: f.write(f"Port {port} is closed.\n") my_socket.close() except socket.timeout: # 仅打印错误,不终止整个进程 print(f"Timeout on port {port}!") except socket.gaierror: print(f"Host error when checking port {port}!") except KeyboardInterrupt: print("Exiting program!") sys.exit() def check_range_ports(ip_host, initial_port, final_port): threads = [] batch_size = 100 # 每批次启动100个线程 current_port = initial_port while current_port <= final_port: # 计算当前批次的结束端口,避免超出范围 end_port = min(current_port + batch_size - 1, final_port) # 启动当前批次的线程 for port in range(current_port, end_port + 1): t = threading.Thread(target=check_port, args=(ip_host, port)) threads.append(t) t.start() # 等待当前批次所有线程完成 for t in threads: t.join() # 重置线程列表,进入下一批次 threads = [] current_port = end_port + 1 if __name__ == "__main__": # 扫描本地3000-4000端口 check_range_ports("127.0.0.1", 3000, 4000)
关键修复点
- 移除异常中的
sys.exit():单个线程的错误仅打印提示,不影响其他线程执行。 - 添加文件写入锁:避免多线程同时写入导致内容丢失或乱码。
- 修正批次端口计算逻辑:用
min()确保最后一批次的端口范围正确,无遗漏。 - 取消守护线程设置:保证线程能完成全部任务再结束。
内容的提问来源于stack exchange,提问作者bringand1
相关产品推荐
相关产品推荐

