##language:zh '''040721 开始定期的进行UC组中的,会课,进行Twisted 的讲解,大家的练习成果在此展示''' -- dreamingk [<>] <> = TwistedTUT 01 = * Twisted TUT 练习1 要求 * 完成一个服务器侦听2020端口 * 用户telnet上去后输入一个url,服务器将这个url的信息抓回返回给用户 * 完成一个客户端,传入一个参数,将得到的信息显示出来 == *inux版本 == ''利用 unix 平台的优点!'' == M$ 版本 == ''' Python!哪里也可以!''' === limodou版本 === {{{ #!python #reactor version from twisted.internet import protocol, reactor, defer, utils from twisted.protocols import basic from twisted.web import client class FingerProtocol(basic.LineReceiver): def lineReceived(self, url): self.factory.getUrl(url ).addErrback(lambda _: "Internal error in server" ).addCallback(lambda m: (self.transport.write(m+"\r\n"), self.transport.loseConnection())) class FingerFactory(protocol.ServerFactory): protocol = FingerProtocol def getUrl(self, url): return client.getPage(url) reactor.listenTCP(2020, FingerFactory()) reactor.run() }}} 去掉了不必要的'''__init__'''函数,改了函数名及参数 {{{ #!python #application version from twisted.application import internet, service from twisted.internet import protocol, reactor, defer from twisted.protocols import basic from twisted.web import client class FingerProtocol(basic.LineReceiver): def lineReceived(self, url): self.factory.getUrl(url ).addErrback(lambda _: "Internal error in server" ).addCallback(lambda m: (self.transport.write(m+"\r\n"), self.transport.loseConnection())) class FingerFactory(protocol.ServerFactory): protocol = FingerProtocol def getUrl(self, url): return client.getPage(url) application = service.Application('finger', uid=1, gid=1) factory = FingerFactory() internet.TCPServer(2020, factory).setServiceParent( service.IServiceCollection(application)) }}} {{{ #!python #client.py from socket import * ADDR = '127.0.0.1' PORT = 2020 def sendraw(data): sendSock = socket(AF_INET, SOCK_STREAM) sendSock.connect((ADDR, PORT)) sendSock.send(data+'\r\n') fp = file('data.txt', 'wb') while 1: text = sendSock.recv(1024) if text: fp.write(text) else: break sendSock.close() fp.close() if __name__ == '__main__': url = raw_input('enter url:') sendraw(url) }}} 存在问题,如果使用telnet好象数据接收不全,但使用客户端程序还可以。 === 0.706版本 === {{{ #!python #server.py from twisted.internet import protocol, reactor, defer from twisted.protocols import basic from twisted.web import client class MyProtocol(basic.LineReceiver): def connectionMade(self): self.transport.write("Welcome,Input A URL:\r\n") def lineReceived(self, url): self.factory.getUser(url).addErrback(lambda _: "Get %s error in server \r\n"%url).addCallback(lambda m: (self.transport.write(m+"\r\n"), self.transport.loseConnection())) class MyFactory(protocol.ServerFactory): protocol = MyProtocol def __init__(self): pass def getUser(self, url): return client.getPage(url) reactor.listenTCP(2020, MyFactory()) print "Server Started!" reactor.run() }}} 我可不喜欢对着一个毫无提示的屏幕. {{{ #!python #client.py import sys from socket import * def main(): Sock = socket(AF_INET, SOCK_STREAM) err=Sock.connect_ex(("127.0.0.1", 2020)) if(err): print "Connect Error" else: page = Sock.recv(8192) sys.stdout.write(page) url = raw_input('') Sock.send(url+'\r\n') page = Sock.recv(8192) sys.stdout.write(page) Sock.close() if __name__ == '__main__': main() }}} 通过测试,发现在输入URL时得输全才能得到结果,如输入 "http://www.163.com" 会出错,而输入 "http://www.163.com/" 就可以 === Zoom.Quiet版本 === ==== for reactor ==== {{{ #!python # -*- coding: gbk -*- # file zwget.py """ reactor version """ from twisted.internet import protocol, reactor, defer, utils from twisted.protocols import basic from twisted.web import client import sys, os, string, time, re class FingerProtocol(basic.LineReceiver): def connectionMade(self): self.transport.write("Hollo! 输入URL吧::\r\n") def lineReceived(self, url): self.factory.getUrl(url ).addErrback(lambda _: "网络连接错误,或是URL错误!" ).addCallback(lambda m: (self.echo(url,m)) ) def echo(self,url,messg): label = time.strftime("%m%d%H%M%S",time.localtime(time.time())) if "bye"==url: self.transport.write("再见!\r\n") self.transport.loseConnection() else: if "URL错误" in messg: self.transport.write(messg+"\r\n") else: open("zgweb-%s.html"%label,"w").write(messg) self.transport.write("抓取内容%s字节\r\n写入zgweb-%s.html\r\n 嗯嗯!再来!\r\n"%( len(messg),label) ) class FingerFactory(protocol.ServerFactory): protocol = FingerProtocol def getUrl(self, url): return client.getPage(url) reactor.listenTCP(2020, FingerFactory()) reactor.run() }}} * 不断根据URL输入,将结果输出为.html文件,直到输入 bye ; * 感谢 0.706 的提示,知道了: {{{ BaseProtocol --+ | Protocol --+ | LineReceiver 中,有从协议继承的 connectionFailed(self) 用以响应协议创建成功! }}} [http://220.248.2.35:7080/share/zqupload/graspOnline/www.twistedmatrix.com/documents/current/api/twisted.internet.protocol.Protocol.html#connectionFailed connectionFailed]in Twisted API ==== for application ==== {{{ #!python # -*- coding: gbk -*- # file zawget.py """ application version """ from twisted.internet import protocol, reactor, defer from twisted.protocols import basic from twisted.web import client from twisted.application import internet, service import sys, os, string, time, re class FingerProtocol(basic.LineReceiver): def connectionMade(self): self.transport.write("Hollo! 输入URL吧::\r\n") def lineReceived(self, url): self.factory.getUrl(url ).addErrback(lambda _: "网络连接错误,或是URL错误!" ).addCallback(lambda m: (self.echo(url,m)) ) def echo(self,url,messg): label = time.strftime("%m%d%H%M%S",time.localtime(time.time())) if "bye"==url: self.transport.write("再见!\r\n") self.transport.loseConnection() else: if "URL错误" in messg: self.transport.write(messg+"\r\n") else: open("zgweb-%s.html"%label,"w").write(messg) self.transport.write("抓取内容%s字节\r\n写入zgweb-%s.html\r\n 嗯嗯!再来!\r\n"%( len(messg),label) ) class FingerFactory(protocol.ServerFactory): protocol = FingerProtocol def getUrl(self, url): return client.getPage(url) application = service.Application('wget', uid=1, gid=1) factory = FingerFactory() internet.TCPServer(2020, factory).setServiceParent( service.IServiceCollection(application)) }}} 果然方便!其实就改最后的服务创建部分,三行而已! ==== for client ==== {{{ #!python # -*- coding: gbk -*- # file zcwget.py """ socket client version """ from socket import * ADDR = '127.0.0.1' PORT = 2020 def client(): Sock = socket(AF_INET, SOCK_STREAM) err=Sock.connect_ex((ADDR, PORT)) if(err): print "连接失败!" else: page = Sock.recv(8192) print page while 1: url = raw_input('') if "bye" in url: break else: Sock.send(url+'\r\n') page = Sock.recv(8192) print page Sock.close() if __name__ == '__main__': client() }}} * 不明白这客户端是什么意思呢? telnet 也算客户端吧? 嗯嗯,就是可以访问我们创建的服务的脚本是也乎!? * 不熟!参考前人的代码,唯一奇怪的是: * Sock.send(url+'\r\n') 为什么不能少 '\r\n' ?? 否则死也! {{{ 我最早是只使用\n就出现你所说的问题。 后来看到transform返回时使用的是\r\n, 我想起来许多协议都要求行结束为\r\n,改过来就行了。 我想finger协议也是如此。使用\r\n而不是\\n应该是标准了。 ======= 2004-07-24 22:57:48 您在来信中写道:======= }}}---Limodou