2014년 9월 17일 수요일

windows 7에서 python twisted 설치 및 echo server 실행

인사이트에서 나온 '트위스티드'를 우연찮게 빌리게 되어 봄.
http://www.insightbook.co.kr/books/programming-insight/twisted-network-programming-essentials-2
파이선이 뭔지도 제대로 모르는 상태이고 그냥 샘플만 끌적이는 것임.

[ installation for Windows 7 ]

윈도우에 트위스티드를 설치하기 위해서는 python 2.7.x 버전이 설치 되어 있어야 한다.

Windows


책에서는 python이 설치된 상태에서 위의 것이 모두 설치 되면 된다고 하는데...
Zope.Interface가 python 2.7이 없다면서 설치가 안된다.

“Python version 2.7 required, which was not found in the registry”

위 message는 "Win 7 64bit 에서 초기 파이썬 설치 시
Install just for me를 체크하지 않고 Install for all users를 선택한 사용자에게 생기는 문제"
라고
http://modular.tistory.com/34  에서 찾게 되어 python을 다시 설치 했음. :(

그 외 방법은 registery를 추가하는 방법이 있는 것 같다.
http://stackoverflow.com/questions/3652625/installing-setuptools-on-64-bit-windows

... 그냥 리눅스를 쓰는게 편할 듯...

twisted가 설치 완료되면 python shell에서 아래와 같이 확인 가능

>>> import twisted
>>> twisted.__version__
'14.0.0'



[ echo server/client example ]

제일 간단한 echo protocol 기반 서버. 하지만 echo protocol은 비록 몇줄 일지라도 RFC 문서도 존재함. 
근데 재미 있는 것은 명령 프롬프트에서 실행하면 잘 되는데 IDLE에서 실행하면 client 쪽에서 계속 connection fail이 발생한다..


[ echo server ]

from twisted.internet import protocol, reactor

class Echo(protocol.Protocol):
    def dataReceived(self, data):
        print "data received"
        self.transport.write(data)

class EchoFactory(protocol.Factory):
    def buildProtocol(self, addr):
        return Echo()

reactor.listenTCP(8888, EchoFactory())
reactor.run()


Reactor를 만들어 TCP 880 port에서 listen하고 connection이 생성 될 때 마다 EchoFactory()를 생성하여 처리하도록 하고 있음 (Reactor 개념은 ......  참조)

Reference를 찾아보니 (python은 처음이라 API reference도 좀 생소하다..)


reactor에서는 networking, threading, event dispatching등의 기능을 해야 하고 
실제 여러 platform, OS에서 동작 하여야 하므로 추상화된 API 로 동일 기능을 제공할 수 밖에 없을 것임. 예를 들어 boost.asio도 기본적인 API로 동일 functionality를 보장하고 os 특화된 기능 (overlapped i/o 같은)을 별도의 class로 떼서 제공을 하니..

reactor interfaces
IReactorCore, IReactorTime, IReactorProcess, IReactorTCP, IReactorSSL, IReactorUDP, IReactorMulticast, IReactorUNIX, IReactorUNIXDatagram, IReactorFDSet, IReactorThreads, IReactorPluggableResolver

echo 서버는 TCP 기반이므로 reactor의 TCP interface method를 구현.


MethodlistenTCPConnects a given protocol factory to the given numeric TCP/IP port.
MethodconnectTCPConnect a TCP client.
reactor의 개념 상 TCP 통신을 위해서 제공하는 API는 connection 관련 단 두개..
connection 이후 server, client 간 read/write 는 위 API의 argument로 제공되는 protocol factory 에서 처리가 된다.

def listenTCP(port, factory, backlog=50, interface=''): (source)
Connects a given protocol factory to the given numeric TCP/IP port.
Parametersporta port number on which to listen
factorytwisted.internet.protocol.ServerFactoryinstance
backlogsize of the listen queue
interfaceThe local IPv4 or IPv6 address to which to bind; defaults to '', ie all IPv4 addresses. To bind to all IPv4 and IPv6 addresses, you must call this method twice.

Server factory class는 아래 링크에서 찾아 볼 수 있고
관련된 protocol들도 명시 되어 있다.



Inherited from Factory:
Class MethodforProtocolCreate a factory for the given protocol.
MethodlogPrefixDescribe this factory for log messages.
MethoddoStartMake sure startFactory is called.
MethoddoStopMake sure stopFactory is called.
MethodstartFactoryThis will be called before I begin listening on a Port or Connector.
MethodstopFactoryThis will be called before I stop listening on all Ports/Connectors.
MethodbuildProtocolCreate an instance of a subclass of Protocol.
echo 서버의 동작(단순 read한 data를 write하여 client로 전달)은 단순하므로 buildProtocol method만 사용하여 echo client 처리를 위한 protocol instance를 생성함.


MethodlogPrefixReturn a prefix matching the class name, to identify log messages related to this protocol instance.
MethoddataReceivedCalled whenever data is received.
MethodconnectionLostCalled when the connection is shut down.
Inherited from BaseProtocol:
MethodmakeConnectionMake a connection to a transport and a server.
MethodconnectionMadeCalled when a connection is made.

참고... 예제라 base protocol을 상속하여 구현하지만 twisted내에도 echo protocol을 제공하고 있음


echo server/client의 동작을 위해
reactor->facory에서 생성된 protocol.dataReceived()에서 data를 받아
transport.write(data)를 해주어 client에 전달하면 끝..



[ echo client ]

from twisted.internet import reactor, protocol

class EchoClient(protocol.Protocol):
    def connectionMade(self):
        self.transport.write("Hello, world!")

    def dataReceived(self, data):
        print "Server said:", data
        self.transport.loseConnection()

class EchoFactory(protocol.ClientFactory):
    def buildProtocol(self, addr):
        return EchoClient()

    def clientConnectionFailed(self, connector, reason):
        print "Connection failed.", reason.getErrorMessage()
        reactor.stop()

    def clientConnectionLost(self, connector, reason):
        print "Connection lost."
        reactor.stop()

reactor.connectTCP("localhost", 8888, EchoFactory())
reactor.run()


reactor.connectTCP를 통해 tcp://localhost:8080 로 connect를 하는 것이고 
reactor에서는 해당 connection을 EchoFactory instance를 만들어 처리하도록 한다.

protocol을 처리하고자 buildProtocol()에서는 EchoClient를 생성하여 echo 동작을 수행하되 connection 오류 상황인 connect가 되지 않는 경우(server가 실행되지 않거나 해당 주소로 접근 불가 시)는 clientConnectionFailed()에서 처리하고
수립되었던 connection이 끊어지는 경우(server에서 connection을 close하거나 physical connection이 끊기 거나)에는 clientConnectionLost()에서 처리하도록 되어 있다.

client 이므로 connection이 성공하면
바로 server로 data를 보내고자  transport.wrtie()를 호출 하여 "hello world!" 전송하고
보내진 "hello world!"메세지는 server에서 다시 client로 보내질 테니
EchoClient.dataReceived()에서 다시 돌려받은 "hello world!" 메세지를  출력하고 끝남.

댓글 없음:

댓글 쓰기