官方文档不怎么友好..哈哈哈
自己写了个
总体按照:https://twistedmatrix.com/documents/current/core/howto/servers.html 来写
twisted总体就是一个循环. 下面我会按照 socket编程 的习惯来说明
第一个例子: 里面有2个类
说简单说明一下:
1. Protocol 类, 内部封装了一个 transport 对象, 这个 transport 内部又封装了 socket 对象.
transort -> twisted.internet.tcp.Server .
综上来说你可以把protocol.transort 认为是一个socket对象, 如果要发送数据可以使用 transport.write
2. Factory类. 用于创建 一个个 Protocol 对象的,即创建一个个socket对象.(其实不是),下面有源码解释
3. 下面的例子都可以使用telnet 来充当客户端
其他的说明在下面代码中
from twisted.internet.selectreactor import SelectReactor
from twisted.internet.protocol import Protocol,Factory
import time
#这一行可以省略. 可以直接 from twisted.internet import reactor
reactor = SelectReactor()
#Protocol 相当于一个个 socket
class Echo(Protocol):
# addr 由工厂传递对方 ip 地址
def __init__(self,addr):
self.addr = addr
print('echo init ,peer addr :' , addr)
#重写的函数, 数据一旦到达
def dataReceived(self, data):
print('datarecvd :', data)
self.transport.write(data)
#socket 一旦 被监听套接字 accept 后
def connectionMade(self):
print('connectionMade ' )
self.transport.write(b'connectionMade')
#对端关闭
def connectionLost(self, reason):
print('connectlost')
#工厂将创建一个个Protocol对象, 你可以把Protocol 对象当作socket来对象
class fa(Factory):
protocol = Echo #buildProtocol 根据这个类属性来创建protocol
#重写了buildProtocol ,默认源码中并没有传递 addr .其他都一样, 每一次有客户端连接都将调用
def buildProtocol(self, addr):
print('buildProtocol : ', addr)
p = self.protocol(addr)
p.factory = self
return p
#listenTcp 先将创建监听套接字,然后用于监听18900端口 ,具体可以看之后的 c 代码解释
reactor.listenTCP(18900,fa(),100)
reactor.run()
#工厂, 即创建一个个 protocol , 其实socket并不是他创建的,只是用他来管理一个个protocol对象
'''
源码: 只留了重要的
#这个clients 内部是真正的socket对象
clients = _accept(bufferingLogger, range(numAccepts),self.socket,_reservedFD)
#获取host
host = socket.getnameinfo(addr, socket.NI_NUMERICHOST | socket.NI_NUMERICSERV)
#获取addr
addr = tuple([host[0]] + list(addr[1:]))
#self.factory 是我们传递进去的工厂, 用来创建一个个protocol对象
protocol = self.factory.buildProtocol(self._buildAddr(addr))
#transport 是将存放accept返回的socket对象
transport = self.transport(skt, protocol, addr, self, s, self.reactor)
#最后把transport存放在protocol 中
protocol.makeConnection(transport)
'''
一般编写服务器时 (用c来解释):
int listenfd = socket(AF_INET, SOCK_STREAM,0) # 创建套接字
#这部分如果看不懂可忽略
struct sockaddr_in serv_addr;
memset(&serv_addr,0,socklen);
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(12345);
serv_addr.sin_family = AF_INET;
#这部分如果看不懂可忽略
#绑定到本地ip port
if(bind(listensock,(SA*)&serv_addr,sizeof(serv_addr)) < 0){
perror("bind");
return 0;
}
#转成监听套接字
if(listen(listensock,BACKLOG) < 0){
perror("listen");
return 0;
}
#以上部分可以全部忽略, 只看下面的
while(1){
#获取socket
int client_sock = accept(listenfd , ... )
#在twisted中在此将创建一个个protocol,内部存放transport ,transport内部存放socket
protocol = factory.buildProtocol(... )
#创建transport对象内部存放 client_sock
trans = transport( client_sock , .... )
#把transport存放在protocol中
protocol.makeConnection(transport)
}
第2个例子:
在上面的例子 直接继承Protocol 或许不太好用,接收到的都是一个个字符
下面改成 LineReceiver ,他也继承自Protocol ,所以你不用担心:
只改了Echo
from twisted.internet.selectreactor import SelectReactor
from twisted.internet.protocol import Protocol,Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.protocols.basic import LineReceiver
import time
reactor = SelectReactor()
from twisted.internet.tcp import Server
class Echo(LineReceiver):
def __init__(self,addr):
self.addr = addr
print('echo init , peer addr:', addr)
#唯一不一样的地方. dataReceived 在LineReceiver自有实现,我们就别去改了
#重写这个函数,这个函数将返回一行行数据 ,根据\r\n来分割
def lineReceived(self, line):
print('lineReceived :' , line)
#发送回去
self.sendLine(b'echo' + line)
#发回去后立刻断开连接
self.transport.loseConnection()
def connectionMade(self):
print('connectionMade :' , type(self.transport), self.transport )
self.transport.write(b'connectionMade')
def connectionLost(self, reason):
print('connectlost')
class fa(Factory):
protocol = Echo
def buildProtocol(self, addr):
print('buildProtocol : ', addr)
p = self.protocol(addr)
p.factory = self
return p
reactor.listenTCP(18900,fa(),100)
reactor.run()
第3个例子: 客户端 , 基于上面的服务器 , 除了一个类变了其他都没变
from twisted.internet.selectreactor import SelectReactor
from twisted.internet.protocol import Protocol,ClientFactory,ReconnectingClientFactory
from twisted.internet.tcp import Connector
#还是没变, 把他看成与服务器通信的socket即可
class Echo(Protocol):
def __init__(self,addr):
self.addr = addr
print('serv addr:', addr)
def dataReceived(self, data):
print('from serv:', data)
def connectionMade(self):
print('connectionMade :' , type(self.transport), self.transport )
self.transport.write(b'Client connectionMade\r\n')
def connectionLost(self, reason):
print('client connectlost :' , reason)
#这里继承了ClientFactory , ClientFactory 继承了Factory ,只是多了些函数罢了
class ClientFa(ClientFactory):
protocol = Echo #创建协议(socket)
#开始连接的时候
def startedConnecting(self, connector:Connector):
print('startedConnecting , ' ,connector )
connector.connect()
#连接失败
def clientConnectionFailed(self, connector, reason):
print('clientConnectionFailed' , connector ,reason)
#连接断开
def clientConnectionLost(self, connector, reason):
print('clientConnectionLost' , connector, reason)
#创建protocol
def buildProtocol(self, addr):
p = self.protocol(addr)
p.fa