由于某些telnet客户端拒绝处理CHARSET否定,并且在我请求其环境变量时也没有发送有用信息,因此我在发送一些特殊字符串后尝试使用设备状态报告。
二进制模式为ON。
首先,我用CSI + 2J清理屏幕,然后将光标设置在第一行,第一列用CSI + 1; 1H。
然后我发送字符串“\ xc3 \ xa9”,这是一个UTF8“é”,并用CSI + 6n请求光标位置。如果光标只移动了一列,我假设客户端的编码是UTF8。
否则,我发送字符串“\ x80 \ x81”。如果客户端的编码是Latin-1,则不应输出任何内容;如果客户端的编码是cp1252,则应该输出一个字符,最后如果客户端的编码是Mac_Roman,则输出2个字符。
问题在于,在所有情况下,CSI + 6n报告的是2列移动,当客户端的编码不是Mac_Roman时,这是不正确的。
我做错了什么或者它是一个已知的错误?有什么想法吗?
Edit2:这是一个工作示例代码,将python脚本作为服务器运行,然后在localhost 4242上telnet进行测试。
#!/usr/bin/python
# -*- coding: utf-8 -*-
import SocketServer
import re
# TELNET commands we need
DO = 253
DONT = 254
WILL = 251
WONT = 252
IAC = 255
SE = 240
SB = 250
SGA = 3
ECHO = 1
BINARY = 0
NAWS = 31
LINEMODE = 34
# ANSI Escape sequence
CSI = u'\x1b['
def cmd(s):
"""Translate from TELNET commands to bytes string"""
return b"".join([chr(x) if isinstance(x, int) else x for x in s])
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
client_charset = "ascii"
def init_session(self):
print "Connection from {}".format(self.client_address)
# negotiating requested options or quit
asking = (IAC, WILL, ECHO, IAC, WILL, SGA, IAC, DO, SGA, IAC, DO, BINARY, IAC, WILL, BINARY, IAC, WONT, LINEMODE, IAC, DONT, LINEMODE)
waiting = set(map(cmd, [(IAC, DO, ECHO), (IAC, DO, SGA), (IAC, WILL, SGA), (IAC, WILL, BINARY), (IAC, DO, BINARY)]))
self.request.sendall(cmd(asking))
data = self.request.recv(1024)
print [ord(x) for x in data]
for x in waiting:
if x not in data:
return False
# retrieve client's naws (terminal size)
asking = (IAC, DO, NAWS)
waiting = cmd((IAC, WILL, NAWS))
self.request.sendall(cmd(asking))
data = self.request.recv(1024)
print [ord(x) for x in data]
if waiting not in data:
return False
data = data.replace(chr(IAC) * 2, chr(IAC))
waiting = cmd((IAC, SB, NAWS, r"(.)(.)(.)(.)", IAC, SE))
r = re.search(waiting, data)
if not r:
return False
a, b, c, d = ord(r.group(1)), ord(r.group(2)), ord(r.group(3)), ord(r.group(4))
columns, rows = 256*a+b, 256*c+d
print "%d columns, %d rows" % (columns, rows)
self.columns, self.rows = columns, rows
# guessing client encoding
self.request.sendall("{0}2J{0}1;1HDeterming your encoding...".format(CSI))
self.request.sendall("{0}2;1H\xc3\xa9{0}6n".format(CSI))
data = self.request.recv(1024)
row, col = map(int, data[2:-1].split(";"))
print row, col
if col == 2:
self.client_charset = "utf-8"
else:
self.request.sendall("{0}3;1H({1}){0}6n".format(CSI, "\x80\x81"))
data = self.request.recv(1024)
row, col = map(int, data[2:-1].split(";"))
print row, col
if col == 3:
self.client_charset = "latin_1"
elif col == 4:
self.client_charset = "cp1252"
elif col == 5:
self.client_charset = "mac_roman"
print self.client_charset
return False # We don't handle any client
def handle(self):
if not self.init_session():
print "Rejecting client"
else:
pass
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
allow_reuse_address = True
if __name__ == "__main__":
# Port 0 means to select an arbitrary unused port
HOST, PORT = "", 4242
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
print "Server starting on port %d" % port
try:
server.serve_forever()
except:
print "Shutting down"
server.shutdown()
server.server_close()