python - 当我向 python 服务器发送 "invalid command"时,TCL 客户端挂起

标签 python sockets tcl

我的设置中有一个 python 服务器和一个 TCL 客户端,它们都在使用端口 8020 的同一台机器上运行。

我基本上在 python 服务器中实现了一些函数来执行一些操作。

我正在尝试在 python 服务器中添加一些异常处理,尤其是当 TCL 客户端试图调用 python 中尚不可用的某些函数时。 python 服务器应提醒 TCL 客户端该功能尚不可用。

我已经复制粘贴了我的代码:-

Python 服务器代码

import socket
import sys
import os

DUT_Browser = ""
host = 'localhost'
port = 8020
print 'Current working Directory:',os.getcwd()


def LogError(message):
    try:
        logfile = open("log.txt", "a")
        try:
            logfile.write(message)
        finally:
            logfile.close()
    except IOError:
        pass

def GetParam(sParams, i):
    params = sParams.split(",")
    p = params[i].strip()
    p = p.strip("\"")

    return p

def Login(sParams):
    print "In method Login with parameters:", sParams

    return 0


def ExecuteKeyword(sCommand):
    vals = sCommand.partition("(")
    sKeyword = vals[0].strip()
    sParams = vals[2].strip()
    # Remove the trailing ")" from the parameters string
    sParams = sParams[:-1]
    #print "KEYWORD: ", sKeyword, "PARAMETERS: ", sParams
    func = getattr(sys.modules[__name__],sKeyword)
    failed = 1
    failed=func(sParams)
    if failed:
        return 1
    else:
        return 0

def clientthread(conn):
    while True:
        keyword = conn.recv(1024)
        errorMsg = 'none'
        failed = 1
        try:
           failed=ExecuteKeyword(keyword)
        except (Exception, FindFailed), err:
        #except Exception, err:
            errorMsg=str(err)
            LogError(errorMsg)
        if failed:
            reply = 'FAIL START' + errorMsg + 'FAIL END'
            print 'ERROR MSG:',reply
        else:
            reply = 'PASS: ' + keyword
        if not keyword:
           break
        print 'SERVER REPLY',reply
        conn.sendall(reply)
        print 'SERVER REPLY SENT'
    conn.close()

sdServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'TCP (SOCK_STREAM) Socket created'

try:
    sdServer.bind((host, port))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()

print 'Socket bind to port:',port,'on host:',host,'is complete'

#Start listening on socket
sdServer.listen(10)
print 'Socket now listening for 10 connections'
while 1:
    #wait to accept a connection - blocking call
    conn, addr = sdServer.accept()
    print 'Connected with ' + addr[0] + ':' + str(addr[1])
    #try:
    clientthread(conn)
    #except socket.error , err:
    #    print str(err)

sdServer.close()

TCL客户端代码

set port 8020
set host localhost
set ntoIP "http://10.218.164.58/"
set sdClient [socket $host $port]
fconfigure $sdClient -buffering line
set ntoGuiCmd start
while {$ntoGuiCmd != "end"} {
    puts "Enter some command for $sdClient"
    set ntoGuiCmd [gets stdin]
    puts $sdClient $ntoGuiCmd
    if {[eof $sdClient]} {close $sdClient}
    gets $sdClient serverMessage
    puts "From Server : $serverMessage"
}

当我从客户端输入以下命令时,它通过并按预期运行 并打印来自服务器的消息。

Login("10.218.164.58",admin,admin,\"FALSE\")

然而,当我使用以下尚未实现的命令时,客户端只是 挂起并且不打印来自服务器的异常,表明它尚未实现。

Logout("10.218.164.58")

我什至尝试使用 wireshark 并注意到服务器确实发送了消息,而且 TCL 客户端似乎已经发送了 ACK 作为响应。所以不太确定为什么“gets”应该挂起。

最佳答案

我不太确定哪里出了问题,但我怀疑问题出在 Tcl 代码中。有很多可能的问题(是否有换行符被传回?)但关键是代码实际上并不是特别地道。这是一个更惯用的版本:

set port 8020
set host localhost
set sdClient [socket $host $port]
fconfigure $sdClient -buffering line
while true {
    puts "Enter some command for $sdClient"
    gets stdin ntoGuiCmd
    if {[eof stdin] || $ntoGuiCmd eq "end"} {
        break
    }
    if {[catch {puts $sdClient $ntoGuiCmd}]} {
        break
    }
    ### Replacement discussed below starts here
    gets $sdClient serverMessage
    if {[eof $sdClient]} {
        break
    }
    puts "From Server: $serverMessage"
    # If multiline messages are possible, extra work is required here!
    ### Replacement ends here
}
close $sdClient

如果您有多行响应,则需要格外小心。最好的方法是阅读它们,直到您知道已经到达响应的末尾(例如,因为服务器告诉您字节数或行数),但这并不总是可行的。如果您假设响应总是适合单个数据包,您可以使用它来读取可用的行(它通过以非阻塞模式从套接字读取来工作当有未读字节时):

fconfigure $sdClient -blocking 0
while {[gets $sdClient serverMessage] >= 0} {
    puts "From Server: $serverMessage"
}
fconfigure $sdClient -blocking 1
if {[eof $sdClient]} {
    break
}

如果响应足够大(取决于操作系统缓冲区等),则不会将其写入一个数据包。那是您真正需要在消息传递协议(protocol)中明确标记响应结束位置的时候。 (反之亦然,只是请求大了才会出问题。)


如果这都是我自己的代码,我很想做一个完全异步的非阻塞客户端:

proc transfer {from to} {
    if {[gets $from line] >= 0} {
        puts $to $line
    } elseif {[eof $from]} {
        exit
    }
}

set sock [socket "localhost" 8020]
fconfigure stdin -blocking 0
fconfigure $sock -blocking 0
fileevent stdin readable [list transfer stdin $sock]
fileevent $sock readable [list transfer $sock stdout]
vwait forever

但是,这是一种非常不同风格的客户端(并且不容易包装到前端 API 中)。

关于python - 当我向 python 服务器发送 "invalid command"时,TCL 客户端挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15420218/

相关文章:

javascript - 正则表达式过滤掉json字符串中的部分键值

java - 服务器发起的客户端-服务器通信

c - 当符号链接(symbolic link)后跟 `..` 时 [file normalize $path] 和 realpath($path) 之间的行为差​​异

linux - 按预期生成 ssh 时的问题({$var} 与 "$var")

python - 使用 Python 从 XAML 中提取数据

python - 为什么使用 numpy 进行矩阵乘法比使用 Python 中的 ctypes 更快?

python - 用于预定义类创建的元类与继承

Python:套接字:处理蜂窝网络上的 TCP 连接

java - Java 和 Python 之间通信的理想格式 "message"?

linux - 如何在 Linux 环境下的 Tcl 中根据文件存在检查终止应用程序