5.Twisted学习

 1 from twisted.application import service, strports
 2 from twisted.internet import protocol, reactor, defer
 3 from twisted.protocols import basic
 4 
 5 class FingerProtocol(basic.LineReceiver):
 6     def lineReceived(self, user):
 7         d = self.factory.getUser(user)
 8 
 9         def onError(err):
10             return b'Internal error in server'
11         d.addErrback(onError)
12 
13         def writeResponse(message):
14             self.transport.write(message + b'\r\n')
15             self.transport.loseConnection()
16         d.addCallback(writeResponse)
17 
18 class FingerFactory(protocol.ServerFactory):
19     protocol = FingerProtocol
20 
21     def __init__(self, users):
22         self.users = users
23 
24     def getUser(self, user):
25         return defer.succeed(self.users.get(user, b"No such user"))
26 
27 class FingerSetterProtocol(basic.LineReceiver):
28     def connectionMade(self):
29         self.lines = []
30 
31     def lineReceived(self, line):
32         self.lines.append(line)
33 
34     def connectionLost(self, reason):
35         user = self.lines[0]
36         status = self.lines[1]
37         self.factory.setUser(user, status)
38 
39 class FingerSetterFactory(protocol.ServerFactory):
40     protocol = FingerSetterProtocol
41 
42     def __init__(self, fingerFactory):
43         self.fingerFactory = fingerFactory
44 
45     def setUser(self, user, status):
46         self.fingerFactory.users[user] = status
47 
48 ff = FingerFactory({b'moshez': b'Happy and well'})
49 fsf = FingerSetterFactory(ff)
50 
51 application = service.Application('finger', uid=1, gid=1)
52 serviceCollection = service.IServiceCollection(application)
53 strports.service("tcp:79", ff).setServiceParent(serviceCollection)
54 strports.service("tcp:1079", fsf).setServiceParent(serviceCollection)

这个项目有两个协议-工厂类,每一个都是application的子程序。更具体地说,setServiceParents方法把两个服务定义为application,实现了IServiceCollections。这两个服务都由应用程序启动。

使用Services让依赖更加合理

使用服务基类,实现泛型行为

 1 from twisted.application import service, strports
 2 from twisted.internet import protocol, reactor, defer
 3 from twisted.protocols import basic
 4 
 5 class FingerProtocol(basic.LineReceiver):
 6     def lineReceived(self, user):
 7         d = self.factory.getUser(user)
 8 
 9         def onError(err):
10             return b'Internal error in server'
11         d.addErrback(onError)
12 
13         def writeResponse(message):
14             self.transport.write(message + b'\r\n')
15             self.transport.loseConnection()
16         d.addCallback(writeResponse)
17 
18 class FingerSetterProtocol(basic.LineReceiver):
19     def connectionMade(self):
20         self.lines = []
21 
22     def lineReceived(self, line):
23         self.lines.append(line)
24 
25     def connectionLost(self,reason):
26         user = self.lines[0]
27         status = self.lines[1]
28         self.factory.setUser(user, status)
29 
30 class FingerService(service.Service):
31     def __init__(self, users):
32         self.users = users
33 
34     def getUser(self, user):
35         return defer.succeed(self.users.get(user, b"No such user"))
36 
37     def setUser(self, user, status):
38         self.users[user] = status
39 
40     def getFingerFactory(self):
41         f = protocol.ServerFactory()
42         f.protocol = FingerProtocol
43         f.getUser = self.getUser
44         return f
45 
46     def getFingerSetterFactory(self):
47         f = protocol.ServerFactory()
48         f.protocol = FingerSetterProtocol
49         f.setUser = self.setUser
50         return f
51 
52 application = service.Application('finger', uid=1, gid=1)
53 f = FingerService({b'moshez': b'Happy and well'})
54 serviceCollection = service.IServiceCollection(application)
55 strports.service("tcp:79", f.getFingerFactory()
56                    ).setServiceParent(serviceCollection)
57 strports.service("tcp:1079", f.getFingerSetterFactory()
58                    ).setServiceParent(serviceCollection)

简化了代码,在一个服务中使用两个协议 1 from twisted.application import service, strports 2 from twisted.internet import protocol, reactor, defer

 3 from twisted.protocols import basic
 4 
 5 class FingerProtocol(basic.LineReceiver):
 6     def lineReceived(self, user):
 7         d = self.factory.getUser(user)
 8 
 9         def onError(err):
10             return b'Internal error in server'
11         d.addErrback(onError)
12 
13         def writeResponse(message):
14             self.transport.write(message + b'\r\n')
15             self.transport.loseConnection()
16         d.addCallback(writeResponse)
17 
18 
19 class FingerService(service.Service):
20     def __init__(self, filename):
21         self.users = {}
22         self.filename = filename
23 
24     def _read(self):
25         with open(self.filename, "rb") as f:
26             for line in f:
27                 user, status = line.split(b':', 1)
28                 user = user.strip()
29                 status = status.strip()
30                 self.users[user] = status
       #这里每30秒刷新一次
31 self.call = reactor.callLater(30, self._read) 32 33 def startService(self): 34 self._read() 35 service.Service.startService(self) 36 37 def stopService(self): 38 service.Service.stopService(self) 39 self.call.cancel() 40 41 def getUser(self, user): 42 return defer.succeed(self.users.get(user, b"No such user")) 43 44 def getFingerFactory(self): 45 f = protocol.ServerFactory() 46 f.protocol = FingerProtocol 47 f.getUser = self.getUser 48 return f 49 50 51 application = service.Application('finger', uid=1, gid=1) 52 f = FingerService('/etc/users') 53 finger = strports.service("tcp:79", f.getFingerFactory()) 54 55 finger.setServiceParent(service.IServiceCollection(application)) 56 f.setServiceParent(service.IServiceCollection(application))

这个版本在一个集中管理的文件中读取消息,而且进行缓存,每30秒刷新一次

在网上进行宣布

也有其他的服务可以产生这种有效的通信。举个例子,在twisted.web里,这个类本身不做基类,而是被给一个资源,表示通过URL可用的树形资源。这个层级结构由Site动态地覆盖,通过getChild。

为了把它集合到Finger应用程序里,我们设置一个新的TCPservice,这个服务器调用Site的心函数来获取资源。

 1 from twisted.application import service, strports
 2 from twisted.internet import protocol, reactor, defer
 3 from twisted.protocols import basic
 4 from twisted.web import resource,server,static
 5 import cgi
 6 
 7 class FingerProtocol(basic.LineReceiver):
 8     def lineReceived(self, user):
 9         d = self.factory.getUser(user)
10 
11         def onError(err):
12             return b'Internal error in server'
13         d.addErrback(onError)
14 
15         def writeResponse(message):
16             self.transport.write(message + b'\r\n')
17             self.transport.loseConnection()
18         d.addCallback(writeResponse)
19 
20 class FingerResource(resource.Resource):
21     def __init__(self,users):
22         self.users=users
23         #继承基类的__init__
24         super(FingerResource, self).__init__()
25     def getChild(self, path, request):
26         messageValue=self.users.get(path)
27         if messageValue:
28             messageValue=messageValue.decode('ascii')
29         if path:
30             path=path.decode('ascii')
31         if messageValue is not None:
32             messageValue=cgi.escape(messageValue)
33             text="<h1>{}</h1><p>{}</p>".format(path,messageValue)
34         else:
35             text="<h1>{}</h1><p>no such path</p>".format(path)
36         text=text.encode('ascii')
37         return static.Data(text,'text/html')
38 class FingerService(service.Service):
39     def __init__(self,filename):
40         self.filename=filename
41         self.users={}
42     def _read(self):
43         self.users.clear()
44         with open(self.filename,'rb')as f:
45             for line in f:
46                 user,status=line.split(b":",1)
47                 user=user.strip()
48                 status=status.strip()
49                 self.users[user]=status
50         self.call=reactor.callLater(30,self._reaf)
51     def getUser(self,user):
52         return defer.succeed(self.users.get(user,b'no such user'))
53     def getFingerFactory(self):
54         f=protocol.ServerFactory()
55         f.protocol=FingerProtocol
56         f.getUser=self.getUser
57         return f
58     def getResource(self):
59         f=FingerResource(self.users)
60         return f
61     def startService(self):
62         self._read()
63         service.Service.stopService(self)
64     def stopService(self):
65         service.Service.stopService(self)
66         self.call.cancel()
67 application=service.Application('finger',uid=1,gid=1)
68 f=FingerService('/finger')
69 serviceCollection=service.IServiceCollection(application)
70 f.setServiceParent(serviceCollection)
71 strports.service("tcp:79",f.getFingerFactory()
72                  ).setServiceParent(serviceCollection)
73 strports.service("tcp:8000",server.Site(f.getResource())
74                  ).setServiceParent(serviceCollection)

在IRC上宣布

IRC客户端通常很像服务器,相应来自网咯的时间。客户服务奖确保切断的连接重新建立,用了很常见的指数退避。

  1 from twisted.application import internet, service, strports
  2 from twisted.internet import protocol, reactor, defer, endpoints
  3 from twisted.words.protocols import irc
  4 from twisted.protocols import basic
  5 from twisted.web import resource, server, static
  6 
  7 import cgi
  8 
  9 class FingerProtocol(basic.LineReceiver):
 10     def lineReceived(self, user):
 11         d = self.factory.getUser(user)
 12 
 13         def onError(err):
 14             return b'Internal error in server'
 15         d.addErrback(onError)
 16 
 17         def writeResponse(message):
 18             self.transport.write(message + b'\r\n')
 19             self.transport.loseConnection()
 20         d.addCallback(writeResponse)
 21 
 22 
 23 class IRCReplyBot(irc.IRCClient):
 24     def connectionMade(self):
 25         self.nickname = self.factory.nickname
 26         irc.IRCClient.connectionMade(self)
 27 
 28     def privmsg(self, user, channel, msg):
 29         user = user.split('!')[0]
 30         if self.nickname.lower() == channel.lower():
 31             d = self.factory.getUser(msg.encode("ascii"))
 32 
 33             def onError(err):
 34                 return b'Internal error in server'
 35             d.addErrback(onError)
 36 
 37             def writeResponse(message):
 38                 message = message.decode("ascii")
 39                 irc.IRCClient.msg(self, user, msg + ': ' + message)
 40             d.addCallback(writeResponse)
 41 
 42 
 43 class FingerService(service.Service):
 44     def __init__(self, filename):
 45         self.filename = filename
 46         self.users = {}
 47 
 48     def _read(self):
 49         self.users.clear()
 50         with open(self.filename, "rb") as f:
 51             for line in f:
 52                 user, status = line.split(b':', 1)
 53                 user = user.strip()
 54                 status = status.strip()
 55                 self.users[user] = status
 56         self.call = reactor.callLater(30, self._read)
 57 
 58     def getUser(self, user):
 59         return defer.succeed(self.users.get(user, b"No such user"))
 60 
 61     def getFingerFactory(self):
 62         f = protocol.ServerFactory()
 63         f.protocol = FingerProtocol
 64         f.getUser = self.getUser
 65         return f
 66 
 67     def getResource(self):
 68         def getData(path, request):
 69             user = self.users.get(path, b"No such users <p/> usage: site/user")
 70             path = path.decode("ascii")
 71             user = user.decode("ascii")
 72             text = '<h1>{}</h1><p>{}</p>'.format(path, user)
 73             text = text.encode("ascii")
 74             return static.Data(text, 'text/html')
 75 
 76         r = resource.Resource()
 77         r.getChild = getData
 78         return r
 79 
 80     def getIRCBot(self, nickname):
 81         f = protocol.ClientFactory()
 82         f.protocol = IRCReplyBot
 83         f.nickname = nickname
 84         f.getUser = self.getUser
 85         return f
 86 
 87     def startService(self):
 88         self._read()
 89         service.Service.startService(self)
 90 
 91     def stopService(self):
 92         service.Service.stopService(self)
 93         self.call.cancel()
 94 
 95 
 96 application = service.Application('finger', uid=1, gid=1)
 97 f = FingerService('/etc/users')
 98 serviceCollection = service.IServiceCollection(application)
 99 f.setServiceParent(serviceCollection)
100 strports.service("tcp:79", f.getFingerFactory()
101                    ).setServiceParent(serviceCollection)
102 strports.service("tcp:8000", server.Site(f.getResource())
103                    ).setServiceParent(serviceCollection)
104 internet.ClientService(
105     endpoints.clientFromString(reactor, "tcp:irc.freenode.org:6667"),
106     f.getIRCBot('fingerbot')).setServiceParent(serviceCollection)

 

posted @ 2018-12-07 19:10  LoseNine  阅读(201)  评论(0编辑  收藏  举报