Python 如何使用诅咒在终端中写入三个不断更新的行?

Python 如何使用诅咒在终端中写入三个不断更新的行?,python,curses,Python,Curses,我有一个程序,需要输出三条不断变化的信息。连接数、经过的时间和拒绝的连接 我尝试在字符串末尾使用'\r'编写它们,并在其他行开始它们自己的输出循环之前打印换行符,认为回车符返回一行。但它们最终都在第一行相互覆盖 我看到过类似的问题,人们建议使用诅咒,但我似乎无法让它发挥作用。我尝试使用addstr()而不是print或sys.stdout.write(),但显然我做得不对,因为它看起来就像我也尝试过使用move(0,0)在每次addstr之后,因为我认为坐标可能是从光标的最后一个位置计算出来的,

我有一个程序,需要输出三条不断变化的信息。连接数、经过的时间和拒绝的连接

我尝试在字符串末尾使用
'\r'
编写它们,并在其他行开始它们自己的输出循环之前打印换行符,认为回车符返回一行。但它们最终都在第一行相互覆盖

我看到过类似的问题,人们建议使用
诅咒
,但我似乎无法让它发挥作用。我尝试使用
addstr()
而不是
print
sys.stdout.write()
,但显然我做得不对,因为它看起来就像我也尝试过使用
move(0,0)
在每次
addstr
之后,因为我认为坐标可能是从光标的最后一个位置计算出来的,但输出看起来与我没有这样做时一样

以下是我当前使用的
诅咒的代码
-

from scapy.all import *
from curses import wrapper 
import argparse, random, socket, sys, time, os, threading, re, subprocess, curses

def main(target):
    try: 
        stdscr.clear()
        curses.noecho()
        curses.cbreak()
        stdscr.keypad(1)

        #things regarding user agents and iptables

            for conn in range(args.connections):
                t = threading.Thread(target=sendPacket, args=(targetIP, args.port, targetHost,random.choice(userAgents)))
                threads.append(t)
                t.start()
                numConn += 1

                try:
                    lock.acquire()
                    stdscr.addstr(0, 0,'{0} Connections Established to {1} '.format(numConn,getIP(target)))
                    stdscr.refresh()
                    #sys.stdout.flush()
                finally:
                    lock.release()
            time.sleep(args.timer)  


        CloseWin()
        sys.exit()
    except KeyboardInterrupt, e:
        lock.acquire()
        stdscr.addstr (5,0,'Exiting {0}'.format(e))
        CloseWin()
        lock.release()
        sys.exit()

#functions that deal with resolving host and IP

def sendPacket(targetIP,targetPort,targetHost,userAgent):
    try:
        #building and sending the packet
        failPacket = 0
        lock.acquire()
        if synack is None:
            stdscr.addstr(1, 0, '{0} Connections refused'.format(failPacket))
            stdscr.refresh()
            failPacket += 1
            return

        #send final packet

        lock.release()
        return
    except Exception,e:
        CloseWin()
        #print e
        lock.release()
        return 



def MeasureTime():
try:
    lock.acquire()
    while True:
        stdscr.addstr(3, 0,'{0} Time elapsed'.format(time.time() - startTime))
        stdscr.refresh()
finally:
    lock.release()

def CloseWin():
try:
    lock.acquire()
    curses.nocbreak()
    stdscr.keypad(0)
    curses.echo()
    curses.endwin()
finally:
    lock.release()

if __name__ == '__main__':

    #args

    stdscr = curses.initscr()

    if args.debug == True:
        wrapper(OneConn(args.target)) #OneConn is the same as the main function except it only opens one connection, so the print is the same
    else:
        startTime = time.time()
        wrapper(main(args.target))
此外,除了写得不正确之外,我似乎无法正确地关闭它,当我使用
ctrl+c
尝试退出时,它似乎停止更新有关数据包的打印输出,但时间仍在继续。我除了关闭终端之外,也找不出办法阻止它


根据@martinaeu的建议尝试添加锁,并编辑了帖子以展示我所做的。结果是,我只能看到第四行中打印和更新的
时间,根本看不到其他打印,并且在不关闭终端的情况下仍然无法退出程序而不是使用
curses
,您只需发出原始代码将光标向后移动三行即可。这将是:

os.write(1, "\x1b[3F")
小心:这些线没有被擦掉。如果打印的新行的长度与旧行的长度相同(例如,因为它们的格式类似于
“foo:%10d”


参考:(其中“CSI”代表“\x1b[”,n是一个十进制可选数字)。

至少您遇到的一些问题可能与多线程有关,因为有多个线程试图同时使用诅咒(至少在逻辑上)。若要同时成功使用它,您可能需要添加一个
对象,使每个线程(包括主线程)必须在使用诅咒API之前获取并在之后发布。@martineau以前从未使用过锁,所以我仔细阅读了它们,并尝试以我认为有意义的方式添加它们。编辑了主要帖子以反映您使用
Lock()的方式
效率有点低,在线程化的
sendPacket()
函数中使用它的方式可能有一个小错误。建议您多读一点关于它们的内容,并开始通过
with
语句将它们用作上下文管理器。这将消除大部分(如果不是全部的话)的需要,最后尝试
/
一些东西(因为
with
将确保调用
release()
,无论是否存在异常,即使有多个
return
语句)。至于最初的问题,我认为
addstr()的位置参数
是相对于他们将输出发送到的屏幕的一角,这意味着每个
sendPacket
线程都需要在不同的行上添加/更新信息,以使它们都可见。您可以将行传递给他们(这里实际上不需要列)创建每个线程时,将其定位为函数的附加参数。@martineau我希望
sendPacket
将其全部写入一行,只需更改发送的数据包数即可。一开始我认为
addstr()
是相对于屏幕的一角,我认为我调用这些行的方式是有意义的,但它似乎不起作用。关于
lock()
,我是否只是将所有
try/finally
内容替换为
with lock: