如何通过已知协议将python程序与第三方程序连接起来?

米切尔·法斯

我正在尝试使用 Go 文本协议(GTP - http://www.lysator.liu.se/~gunnar/gtp/与程序(GoGui - https://sourceforge.net/projects/gogui/交互),其中有它的文档在这里(链接也可以在以前的网站上找到。)

所以我写了一些代码来至少让 GoGui 承认我的程序的存在:

import sys
import engine
import input_processing

for line in sys.stdin:
    if line == 'name\n':
        sys.stdout.write(' Muizz-Bot\n\n')
    if line == 'protocol_version\n':
        sys.stdout.write('2\n\n')
    if line == 'version\n':
        sys.stdout.write('')

现在这本身似乎并不不合理,但导致 GoGui 给我以下错误: 在此处输入图片说明

这当然是个问题。所以我认为我在编程中的某个地方犯了一个错误,但是当我简单地通过 Visual Studio 运行程序时,一切都按预期进行:http://i.imgur.com/JjDWgVD.png

这让我认为问题在于两个应用程序的接口,也许我应该查看 stdin 和 stdout 以外的其他功能。有谁知道这里可能出了什么问题?

编辑评论:我目前正在处理的命令解析代码(整体)如下所示:

import sys

commands = ['protocol_version', 'name', 'version', 'list_commands', 'known_command', 'quit', 'boardsize', 
            'clear_board', 'komi', 'play', 'genmove']

pre_game_out = ['2','Muizz-Bot','']

# Define all output functions
def list_commands():
    out = '\n'.join(commands)
    return(out)
def known():
    return(True)
def quit():
    return(None)
def boardsize():
    return(None)
def clear_board():
    return(None)
def komi():
    return(None)
def play():
    return(None)
def genmove():
    return("A1")

# Create dictionary to point to all functions.
output = {'list_commands':list_commands, 'known_command':known, 'quit':quit, 'boardsize':boardsize, 
            'clear_board':clear_board, 'komi':komi, 'play':play, 'genmove':genmove}

# Define the function that will pass the commands and write outputs.
def parse(line):
    if line.strip() in commands:
        i = commands.index(line.strip())
        if i<3:
            sys.stdout.write('= '+ pre_game_out[i]+'\n\n')
            sys.stdout.flush()
        else:
            sys.stdout.write('= ' + output[line.strip()]() + '\n\n')
            sys.stdout.flush()

对于预处理:

def input(inp):
    # Remove control characters
    inp = inp.replace('\r', '')
    inp = inp.replace(' ', '')
    inp = inp.split('#', 1)[0]
    inp = inp.replace('\t', ' ')

    # Check if empty
    if inp.isspace() or inp==None or inp=='':
        return
    else:
        return(inp)
泽维尔

您没有刷新响应,因此不会将任何内容发送回调用方(因为命令不够大,无法触发自动缓冲区刷新)。此外,在浏览协议文档时,它清楚地表明您的响应应该采用= response\n\n这样的形式,即使您正在冲洗它,它也可能仍然不起作用。

尝试使用类似的东西:

import sys

for line in sys.stdin:
    if line.strip() == 'name':
        sys.stdout.write('= Muizz-Bot\n\n')
        sys.stdout.flush()
    elif line.strip() == 'protocol_version':
        sys.stdout.write('= 2\n\n')
        sys.stdout.flush()
    elif line.strip() == 'version':
        sys.stdout.write('=\n\n')
        sys.stdout.flush()

您可能想要创建一个简单的函数来解析命令/响应而不是重复代码,tho。此外,这可能不会(完全)工作,因为协议文档指出您需要实现相当多的命令 ( 6.1 Required Commands) 但它应该让您开始。

更新- 这是一种使其更易于管理并符合规范的方法 - 您可以为每个命令创建一个函数,以便您可以根据需要轻松添加/删除它们,例如:

def cmd_name(*args):
    return "Muizz-Bot"

def cmd_protocol_version(*args):
    return 2

def cmd_version(*args):
    return ""

def cmd_list_commands(*args):
    return " ".join(x[4:] for x in globals() if x[:4] == "cmd_")

def cmd_known_command(*args):
    commands = {x[4:] for x in globals() if x[:4] == "cmd_"}
    return "true" if args and args[0] in commands else "false"

# etc.

这里所有的命令功能前缀为“cmd_”(与cmd_list_commands()cmd_known_command()使用这一事实在全局命名空间检查命令功能),但你也可以将它们移动到不同的模块,然后“扫描”模块来代替。有了这样的结构,添加新命令非常容易,例如添加所需的quit命令,您只需要定义它:

def cmd_quit(*args):
    raise EOFError()  # we'll use EOFError to denote an exit state bellow

此外,我们将在下面处理命令需要返回错误的情况 - 您需要从函数中执行的所有操作是 toraise ValueError("error response")并且它将作为错误发送回来。

一旦您将一组命令添加为函数,您只需要解析输入命令,使用正确的参数调用正确的函数并打印回响应:

def call_command(command):
    command = "".join(x for x in command if 31 < ord(x) < 127 or x == "\t")  # 3.1.1
    command = command.strip()  # 3.1.4
    if not command:  # ... return if there's nothing to do
        return
    command = command.split()  # split to get the [id], cmd, [arg1, arg2, ...] structure
    try:  # try to convert to int the first slice to check for command ID
        command_id = int(command[0])
        command_args = command[2:] if len(command) > 2 else []  # args or an empty list
        command = command[1]  # command name
    except ValueError:  # failed, no command ID present
        command_id = ""  # set it to blank
        command_args = command[1:] if len(command) > 1 else []  # args or an empty list
        command = command[0]  # command name
    # now, lets try to call our command as cmd_<command name> function and get its response
    try:
        response = globals()["cmd_" + command](*command_args)
        if response != "":  # response not empty, prepend it with space as per 3.4
            response = " {}".format(response)
        sys.stdout.write("={}{}\n\n".format(command_id, response))
    except KeyError:  # unknown command, return standard error as per 3.6
        sys.stdout.write("?{} unknown command\n\n".format(command_id))
    except ValueError as e:  # the called function raised a ValueError
        sys.stdout.write("?{} {}\n\n".format(command_id, e))
    except EOFError:  # a special case when we need to quit
        sys.stdout.write("={}\n\n".format(command_id))
        sys.stdout.flush()
        sys.exit(0)
    sys.stdout.flush()  # flush the STDOUT

最后,您所需要的只是听您的 STDIN 并将命令行转发到这个函数来完成繁重的工作。在这方面,我实际上是从您的 STDIN 中明确地逐行读取,而不是尝试对其进行迭代,因为它是一种更安全的方法,因此:

if __name__ == "__main__":  # make sure we're executing instead of importing this script
    while True:  # main loop
        try:
            line = sys.stdin.readline()  # read a line from STDIN
            if not line:  # reached the end of STDIN
                break  # exit the main loop
            call_command(line)  # call our command
        except Exception:  # too broad, but we don't care at this point as we're exiting
            break  # exit the main loop

当然,正如我之前提到的,将您的命令打包在一个单独的模块中可能是一个更好的主意,但这至少应该让您知道如何进行“关注点分离”,这样您就可以担心响应您的命令而不是关于他们如何被呼叫以及他们如何回应呼叫者。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在Spring中自动将带有注释的第三方类连接起来?

来自分类Dev

将第三方程序集复制到子文件夹

来自分类Dev

我想通过 web 服务将 android 应用程序与 sql server 连接起来

来自分类Dev

如何安装第三方程序并使它们显示在“ Dash主页”菜单中?

来自分类Dev

如何使用第三方程序自动检查单选按钮

来自分类Dev

Python:如何安装第三方程序包并使其他团队可以使用

来自分类Dev

OpenShift v3 将应用程序与 redis 连接起来。连接被拒绝

来自分类Dev

如何将odoo与体式连接起来?

来自分类Dev

将 Java 与 Python Flask 连接起来

来自分类Dev

如何通过gpplot中的不同组将点与线连接起来?

来自分类Dev

如何避免由于第三方程序包引起的BeanCreationException导致Spring应用程序失败

来自分类Dev

如何通过第三方应用程序访问Yii2(HumHub)

来自分类Dev

如何将字段添加到第三方应用程序模型?

来自分类Dev

如何在Go中包含来自第三方程序包的标头?

来自分类Dev

如何在不使用第三方程序的情况下重新映射OSX键盘?

来自分类Dev

Python:扩展从使用工厂方法的第三方程序包返回的类/对象

来自分类Dev

解决第三方程序包中的bean冲突

来自分类Dev

解决第三方程序包中的bean冲突

来自分类Dev

强制执行特定版本的第三方程序集

来自分类Dev

在没有第三方程序的情况下禁用macOS中的密钥

来自分类Dev

如何使用Count函数将三个表连接起来也返回零结果?

来自分类Dev

如何将哪个名为startActivity的第三方应用程序告诉我的应用程序

来自分类Dev

将IPcamera(DCS-930L)连接到第三方C#wpf应用程序

来自分类Dev

如何通过特殊字符将php中的两个数组元素值连接起来?

来自分类Dev

Django:将第三方应用程序用作Django应用程序

来自分类Dev

通过第三方应用程序通过Internet进行远程访问

来自分类Dev

如何通过Azure AD B2C将第三方IDP的刷新令牌传递给应用程序?

来自分类Dev

如何通过没有第三方邮件帐户的Play框架应用程序发送邮件?

来自分类Dev

如何在Android中杀死/处理空闲线程(通过调用第三方应用程序阻止)

Related 相关文章

  1. 1

    如何在Spring中自动将带有注释的第三方类连接起来?

  2. 2

    将第三方程序集复制到子文件夹

  3. 3

    我想通过 web 服务将 android 应用程序与 sql server 连接起来

  4. 4

    如何安装第三方程序并使它们显示在“ Dash主页”菜单中?

  5. 5

    如何使用第三方程序自动检查单选按钮

  6. 6

    Python:如何安装第三方程序包并使其他团队可以使用

  7. 7

    OpenShift v3 将应用程序与 redis 连接起来。连接被拒绝

  8. 8

    如何将odoo与体式连接起来?

  9. 9

    将 Java 与 Python Flask 连接起来

  10. 10

    如何通过gpplot中的不同组将点与线连接起来?

  11. 11

    如何避免由于第三方程序包引起的BeanCreationException导致Spring应用程序失败

  12. 12

    如何通过第三方应用程序访问Yii2(HumHub)

  13. 13

    如何将字段添加到第三方应用程序模型?

  14. 14

    如何在Go中包含来自第三方程序包的标头?

  15. 15

    如何在不使用第三方程序的情况下重新映射OSX键盘?

  16. 16

    Python:扩展从使用工厂方法的第三方程序包返回的类/对象

  17. 17

    解决第三方程序包中的bean冲突

  18. 18

    解决第三方程序包中的bean冲突

  19. 19

    强制执行特定版本的第三方程序集

  20. 20

    在没有第三方程序的情况下禁用macOS中的密钥

  21. 21

    如何使用Count函数将三个表连接起来也返回零结果?

  22. 22

    如何将哪个名为startActivity的第三方应用程序告诉我的应用程序

  23. 23

    将IPcamera(DCS-930L)连接到第三方C#wpf应用程序

  24. 24

    如何通过特殊字符将php中的两个数组元素值连接起来?

  25. 25

    Django:将第三方应用程序用作Django应用程序

  26. 26

    通过第三方应用程序通过Internet进行远程访问

  27. 27

    如何通过Azure AD B2C将第三方IDP的刷新令牌传递给应用程序?

  28. 28

    如何通过没有第三方邮件帐户的Play框架应用程序发送邮件?

  29. 29

    如何在Android中杀死/处理空闲线程(通过调用第三方应用程序阻止)

热门标签

归档