1.Twisted框架構建簡單的C/Sreact
要寫一個基於twisted框架的服務器,你要實現事件處理器,它處理諸如一個新的客戶端鏈接、新的數據到達和客戶端鏈接中斷等狀況。瀏覽器
在Twisted中,你的事件處理器定義在一個protocol中;你也須要一個factory, 當一個新的鏈接到達時它可以構造這個protocol對象,可是若是你僅僅想建立一個自定義的Protocol類的實例的話,你可使用來自 Twisted的factory,Factory類在模塊twisted.internet.protocol中。當你寫你的protocol時,使用twisted.internet.protocol模塊中的Protocol做爲你的父類。服務器
當你獲得一個鏈接時,事件處理器connectionMade被調用;架構
當你丟失一個鏈接時,connectionLost被調用;app
從客戶端接受數據使用處理器dataReceived;框架
可是你不能使用事件處理策略向客戶端發送數據;要向客戶端發送數據,你能夠使用self.transport,它有一個write方法。它也有一個client屬性,其中包含了客戶端的地址(主機名和端口),即self.transport.client。socket
Eg:函數
twisted server:測試
[cpp]
ui
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory
# 定義你Protocol類
class SimpleLogger(Protocol):
def connectionMade(self):
print 'Got connection from', self.transport.client #self.transport.client =客戶端主機名和端口
def connectionLost(self, reason):
print self.transport.client, 'disconnected'
def dataReceived(self, data):
print data
# 實例化Factory
factory = Factory()
# 設置factory的protocol屬性以便它知道使用哪一個protocol與客戶端通訊(這就是所謂的你的自定義
# protocol)
factory.protocol = SimpleLogger
# 監聽指定的端口
reactor.listenTCP(1234, factory)
# 開始運行主程序
reactor.run()
測試的cilent端:
[cpp]
#socket client end
from socket import *
s=socket(AF_INET,SOCK_STREAM)
remote_host=gethostname()
print 'remote_ip:',remote_host
port=1234
s.connect((remote_host,port)) #發起鏈接
'''
socket對象的getpeername()和getsockname()方法都返回包含一個IP地址和端口的二元組
(這個二元組的形式就像你傳遞給connect和bind的)。
getpeername返回所鏈接的遠程socket的地址和端口,getsockname返回關於本地socket的相同信息。
'''
print("Connected from",s.getsockname()) ##返回本地IP和端口
print("Connected to",s.getpeername()) ##返回服務端IP和端口
s.send('i am form client')
#print 'what i got from select server is:'
#print s.recv(1024)
'''
send,sendto,recv和recvfrom方法都有一個可選的參數flags,默認值爲0。
你能夠經過對socket.MSG_*變量進行組合(按位或)來創建flags的值。
這些值因平臺而有所不一樣,可是最通用的值以下所示:
MSG_OOB:處理帶外數據(既TCP緊急數據)。
MSG_DONTROUTE:不使用路由表;直接發送到接口。
MSG_PEEK:返回等待的數據且不把它們從隊列中刪除。
'''
運行結果:
server端:
[cpp]
>>> ================================ RESTART ================================
>>>
Got connection from ('172.22.144.167', 5466)
i am form client
client 端:
[cpp]
>>> ================================ RESTART ================================
>>>
remote_ip: PC-200910021344
('Connected from', ('172.22.144.167', 5466))
('Connected to', ('172.22.144.167', 1234))
>>>
2.自定義Protocol--利用LineReceiver類做爲父類
模塊twisted.protocols.basic中包含了幾個有用的已存在的protocol,其中的LineReceiver執行dataReceived並在接受到了一個完整的行時調用事件處理器lineReceived。若是當你在接受數據時除了使用lineReceived,還要作些別的,那麼你可使用LineReceiver定義的名爲rawDataReceived事件處理器。
Eg:
Server端:
[cpp]
from twisted.internet import reactor
from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
class SimpleLogger(LineReceiver):
def connectionMade(self):
print 'Got connection from', self.transport.client
def connectionLost(self, reason):
print self.transport.client, 'disconnected'
#注意必須接收到完整的行(即遇到\r\n結束標誌)時該函數才能成功執行
def lineReceived(self, line):
print line
length=len(line)
responsemsg='Dear cilent,I have received '+str(length)+' bytes from you\r\n'
self.transport.write(responsemsg)#向客戶端發送數據
factory = Factory()
factory.protocol = SimpleLogger
reactor.listenTCP(1234, factory)
reactor.run()
Client端:
[cpp]
#socket client end
from socket import *
s=socket(AF_INET,SOCK_STREAM)
remote_host=gethostname()
print 'remote_host:',remote_host
port=1234
s.connect((remote_host,port)) #發起鏈接
print("Connected from",s.getsockname()) ##返回本地IP和端口
print("Connected to",s.getpeername()) ##返回服務端IP和端口
s.send('i am form client\r\n')#發送一行字符串(以\r\n 結束)到服務器端
s.send('next message\r\n')
print 'the msg i got from select server is:'
print s.recv(1024)
運行結果:
Server端:
[cpp]
>>> ================================ RESTART ================================
>>>
Got connection from ('172.22.144.167', 9668)
i am form client
next message
Client端:
[cpp]
>>> ================================ RESTART ================================
>>>
remote_host: PC-200910021344
('Connected from', ('172.22.144.167', 9668))
('Connected to', ('172.22.144.167', 1234))
the msg i got from select server is:
Dear cilent,I have received 16 bytes from you
Dear cilent,I have received 12 bytes from you
>>>
3.使用twisted框架建立Web服務器
Web Server 端:
[cpp]
#Main Point:Build Web Server
from twisted.internet import protocol,reactor
from twisted.protocols import basic
class SimpleLogger(basic.LineReceiver):
def connectionMade(self):
print 'Got connection from', self.transport.client
def connectionLost(self, reason):
print self.transport.client, 'disconnected'
def lineReceived(self,line):
print 'data from client are as followings:'
print line
responseData="Welcome to Twisted World!\r\n"
self.transport.write(responseData)
self.transport.loseConnection() #終止鏈接
# 實例化protocol.ServerFactory()
'''
protocolp.py
class ServerFactory(Factory):
"""Subclass this to indicate that your protocol.Factory is only usable for servers.
"""
'''
factory = protocol.ServerFactory()# ***0120 protocol.ServerFactory()
factory.protocol = SimpleLogger
reactor.listenTCP(6688, factory)
reactor.run()
瀏覽器客戶端測試結果:
Server端運行結果:
[cpp] view plaincopy
>>> ================================ RESTART ================================
>>>
Got connection from ('172.22.144.167', 10293)
Got connection from ('172.22.144.167', 10294)
Got connection from ('172.22.144.167', 10297)
data from client are as followings:
GET / HTTP/1.1
('172.22.144.167', 10297) disconnected
Got connection from ('172.22.144.167', 10298)
data from client are as followings:
GET /favicon.ico HTTP/1.1
('172.22.144.167', 10298) disconnected
('172.22.144.167', 10293) disconnected
('172.22.144.167', 10294) disconnected
4. http請求和響應報文
功能:
返回客戶端的請求信息(http請求報文)
Web Server端代碼:
[cpp] view plaincopy
from twisted.protocols import basic
from twisted.internet import protocol,reactor
class HttpEchoProtocol(basic.LineReceiver):
def __init__(self):
self.lines=[]
self.gotRequest=False
def lineReceived(self,line):
self.lines.append(line)
if not line and not self.gotRequest:
#0121
print 'the msg browser client send to me(http request head) is:'
for e in self.lines:
print e
#
self.sendResponse()
self.gotRequest=True
def sendResponse(self):
#0121 "\r\n".join(self.lines) 列表中的每一條請求消息字符串均用\r\n鏈接起來
responseBody="Dear Client,the msg you sent to me are as followings:\r\n\r\n"+"\r\n".join(self.lines)
#send msg to the browser client 0121
#http response head 0121
self.sendLine("HTTP/1.0 200 OK") #請求成功 0121 (必須) senfLine自動在消息字符串末尾添加\r\n
self.sendLine("Content-Type: text/plain")
self.sendLine("Content-Length: %i"%len(responseBody))
#下面兩行語句[1][2]等價 #0121
#self.sendLine("") #http頭結束標誌 (必須) \r\n [1]
self.transport.write("\r\n") #[2]
self.transport.write(responseBody) #向客戶端發送數據
self.transport.loseConnection() #終止鏈接
f=protocol.ServerFactory()
f.protocol=HttpEchoProtocol
reactor.listenTCP(5000,f)
reactor.run()
瀏覽器測試結果:
服務器端運行結果: