天天看點

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)      

轉載于:https://www.cnblogs.com/losenine/p/10084572.html