前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python模块:telnetlib

Python模块:telnetlib

作者头像
不可言诉的深渊
发布2019-07-26 17:02:46
2.7K0
发布2019-07-26 17:02:46
举报

这学期要交一个作品,我同学打算做一个聊天软件,一个聊天软件无非就是两个程序:一个客户端,一个服务器。服务器我之前写出来了,不清楚的可以参考一下这篇文章:虚拟茶话会(2):再次实现

下面来开始编写客户端,在编写客户端之前,我们首先来想一下之前那个服务器我是如何进行连接测试的,很明显是命令提示符下使用telnet。但是这学期交的作品必须要有图形界面,所以客户端必须自己实现。我同学在实现这个客户端时总是出现各种问题,而且我看他的代码有些也不懂,主要是因为里面有一个我只是听说还没有用过的模块——telnetlib。我首先是上网查了一下telnetlib模块,结果发现它是用来处理telnet连接的。telnet连接现在已经用得非常少了,因为它是明文传输,极度不安全!但是拿它做课程设计绰绰有余。本来我不想学这个模块,但是为了帮他完成这次的课程设计,就当是多学一个模块吧。今天我就是稍微学一下这个模块,不会写一个GUI客户端,文章最后也只能先写一个cmd客户端,GUI客户端先让他自己尝试,他要不会我就下周末写一个给他参考,如果他在下周末之前弄出来GUI客户端那我就不继续了。

言归正传,我们首先来看一下telnetlib模块到底是什么,这个模块里有哪些东西。首先import telnetlib,然后help(telnetlib)即可,如图所示。

稍微翻译一下NAME下面那句话:telnetlib——TELNET客户端类。然后就是描述和一个例子,这些不用管。直接看例子下面的Note那一段,为了确保连贯性,我把Note那一段和它后面几段放一起。

我稍微翻译一下这几段内容:

注意:read_all方法直到结束才开始读——它只是读一些数据——但是它保证至少读一个字节除非碰到了结束符。

将Telnet对象传递给选择器为了等待直到有更多数据可用是可能的。注意在这种情况下,即使过去在套接字上有数据,read_eager方法可能会返回一个空字节,因为协议可能会把数据吃了。这就是有些情况下需要EOFError来区分“无数据”和“连接关闭”的原因(因为套接字在关闭时似乎在准备读取)。

按如下要求做:

  • 选择协议(这个我瞎翻译的,我也不知道该怎么翻

  • 超时应该是连接对象固有的属性而不是一个仅仅只在一个读方法(读方法有很多,下面会介绍)调用时的选项。

然后就是模块中有哪些类,可以发现这个模块中只有一个类——这个类继承自object。下面来看一下这个类的定义以及它的一些方法是如何使用的。

稍微翻译一下这一部分的内容,从class Telnet下面一行开始。

Telnet连接类

这个类的一个实例代表一个指向telnet服务器的连接,这个实例一开始没有连接;open方法必须被用来建立一个连接。当然,主机名和可选择的端口号也可以传递给构造器。

不要尝试重新打开一个已经有连接的实例。

这个类有许多read_打头的方法。注意:当连接的结束位置被读取,它们中有一些会引发EOFError异常,因为有其他原因,它们会返回一个空字符串。请看单个方法的文档字符串。

read_until(expected, [timeout])

一直读,知道出现了被期望的字符串,或者碰见超时(默认没有超时);可以阻塞。

read_all()

读取所有数据直到结束;可以阻塞。

read_some()

至少读一个字节或者读到结束;可以阻塞。

read_very_eager()

读取所有已经排好队(在一个队列里)或者在套接字上的可用数据,没有阻塞。

read_eager()

读取部分已经排好队的数据,或者一些在套接字上的可用数据,没有阻塞。

read_lazy()

读取所有在原始队列中的数据(这些数据需要先处理),没有执行任何套接字的I/O操作。

read_very_lazy()

读取被处理过的数据所在的队列中的所有数据,没有执行任何套接字的I/O操作。(这里也是瞎翻译的

read_sb_data()

读取在(SB...SE)序列之间的可用数据,不能阻塞。

set_option_negotiation_callback(callback)

每次一个telnet选项在输入流上被读取,这个callback参数(如果被设置)伴随着如下参数被调用:

callback(telnet socket, command, option)

当没有option参数时,option参数会是chr(0)(就是0的ASCII码——'\0')。

然后,没有其他操作被telnetlib执行。

方法被定义在这里:

__del__(self)

析构器——关闭这个连接。

__enter__(self)

__exit__(self, type, value, traceback)

__init__(self, host=None, port=0, timeout=<object object at 0x00000123DDE7B120>)

构造器。

当被调用时没有参数,创建一个无连接的实例。如果有一个主机名参数,它会连接这个实例,端口号和超时是可选参数。

close(self)

关闭这个连接。

expect(self, list, timeout=None)

一直读,直到和正则表达式列表中的一个元素所匹配。

第一个参数是一个正则表达式列表,可以是被编译过的(re.RegexObject实例),也可以是没有被编译的(字符串)可选的第二个参数是超时,单位秒;默认没有超时。

返回三个元素构成的一个元组:与读取内容所匹配的正则表达式在列表中的第一个索引,被返回的匹配对象,以及包括匹配到的字符串在内的所有读取的数据。

如果结束符被读取并且没有内容之前被读取,引发EOFError异常。否则,当没有匹配时,返回(-1, None, text)在这里text参数是目前被接收到的内容(如果出现了超时,可能是一个空字符串)。

如果一个正则表达式以贪婪匹配(例如'.*')结束,或者如果有不止一个正则表达式可以匹配相同的输入信息,这个结果是不确定的,可能取决于I/O时序。

fileno()

返回被套接字对象内部使用的文件描述符。

fill_rawq(self)

确切的说,通过调用一个名叫recv的系统函数来填充原始队列。如果短时间内没有数据可用,就阻塞。当连接被关闭时,设置Telnet类的实例的eof属性。

get_socket(self)

返回一个被内部使用的套接字对象。

interact(self)

交互功能,模拟一个非常愚蠢的telnet客户端。

listener(self)

关于mt_interact()的帮手——这个函数在另一个线程中执行。

msg(self, msg, *args)

当调试等级大于0时,输出一个调试信息。

如果有额外的参数,它们在使用标准字符串格式运算符的消息中被替代。

mt_interact(self)

interact(self)方法的多线程版本。

open(self, host, port=0, timeout=<object object at 0x0000024C0F5DB750>)

连接到一台主机。

可选的第二个参数是端口号(默认是标准的telnet端口号(端口:23))。

不要尝试重新打开一个已经被连接的实例。

process_rawq(self)

从原始数据队列转移到被处理过的数据所在的队列,当连接被关闭时,设置Telnet类的实例的eof属性,除非在应用间通信的序列中,否则不能阻塞。

rawq_getchar(self)

从原始队列中获取下一个字符。

如果短时间内没有可用数据,就阻塞。当连接被关闭时,引发EOFError异常。

read_all(self)

读取所有数据直到结束;一直阻塞直到连接关闭。

read_eager(self)

毫不犹豫地读取可用数据。

如果连接被关闭,并且没有可用的已经被处理的数据,就引发EOFError异常。在其他情况下,如果没有被处理的可用数据,就返回空字节。除非在应用间通信的序列中,否则不能阻塞。

read_lazy(self)

处理并返回已经在队列中的数据(惰性)。

如果连接被关闭,并且没有可用数据,就引发EOFError异常。在其他情况下,如果没有可用数据,就返回空字节。除非在应用间通信的序列中,否则不能阻塞。

read_sb_data(self)

返回任何在SB...SE序列中的可用数据。

如果没有可用的SB...SE序列,返回空字节。应该仅仅只在看见SB或者SE命令后被调用。当一个新的SB命令被发现,老的不能识别的SB命令将会被抛弃。不能阻塞。

read_some(self)

除非读到了结束符,否则至少读取被处理的数据的一个字节。

如果读到了eof,返回空字节。如果短时间内没有可用数据就阻塞。(有意思,这个函数一会可能要用,因为我想通过阻塞控制GIL锁,此时接收数据行为的雏形已经出现了。)

read_until(self, match, timeout=None)

一直读,直到遇见一个被传入的字符串或者超时。

当没找到match时,可能会返回一个空字符串而不是任何可用的东西。如果连接被关闭并且没有被处理的数据可用,就引发EOFError异常。

read_very_eager(self)

读取可能的所有东西,没有I/O阻塞(急切)。

如果连接被关闭并且没有被处理的数据可用,就引发EOFError异常。在其他情况下如果没有被处理的数据可用就返回空字节。除非在一个应用间通信的序列中,否则不能阻塞。

read_very_lazy(self)

返回任何在被处理过的数据所在的队列中的所有可用数据(非常懒惰)。

如果连接被关闭并且没有可用数据,就引发EOFError异常。在其他情况下如果没有被处理的可用数据,就返回空字节。不能阻塞。

set_debuglevel(self, debuglevel)

设置调试级别。

级别越高,(在标准输出流上)你得到的调试输出信息就越多。

set_option_negotiation_callback(self, callback)

提供一个在每次接收到一个telnet选项后被调用的回调函数。

sock_avail(self)

测试在套接字上是否有数据可用。

write(self, buffer)

向套接字中写入一个字符串,折叠任何应用间通信的字符。

如果连接被阻塞,就可以阻塞。如果连接被关闭,可能会引发OSError异常。(此时发送数据的行为的雏形也出现了)。

(上面的翻译可能会有小错误,尽请谅解!)不用往下继续看了,发送数据的操作和接收数据的操作都已经清楚了。这个客户端使用两个线程,一个负责发送数据,一个接收接收数据。发送数据的操作是一个死循环,如果要发送的数据是"logout "打头的一行字符串,就结束这个操作。接收数据的操作也是一个死循环,如果碰到了结束位置,就结束该操作。最终的代码如图所示。

通过注释,大家理解起来应该不难,我就不做详细的解释了。下面看一下运行结果。运行客户端之前一定要先运行服务器!!!

差不多了,我暂时先给出一个GUI客户端的实现思路,首先是登录界面,登录界面就是三个单行输入和三个提示输入的文本框(主机名,端口号和用户名),一个执行登录的按钮(登陆成功跳转到聊天室,登录失败就弹出信息)。然后就是聊天室界面,聊天室界面有两个文本框,其中一个是用于接受数据的多行只读文本框,还有一个是单行用于发送数据的可编辑文本框。另外还有四个按钮——发送数据,查看聊天室里都有谁,查看谁已登录,退出。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-11-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python机器学习算法说书人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档