[python] UDP sample server using gevent and scapy test Develop Tip

최근에 검색을 하다가 홍민희라는분의 블로깅 내용을 보게 되었는데,
아주 감명깊었습니다.

그 내용 중 비동기 IO에 대한 생각 이라는 글도 특히나 재미있었습니다.

결국 Node.js 도 이런 비동기 IO를 V8 JavaScript 엔진에 녹여놓고 
JavaScript를 이용한 비동기 서비스를 제공하는 것이 그 가장 큰 장점이라 하더군요.

암튼 이런 이유로 파이썬의 gevent라는 것이 이런 비동기 관련 작업을 할 수 있게 해주는
파이썬의 모듈입니다.

암튼 필요에 따라 UDP 간단 서버를 gevent를 이용하려 만들어 보려 합니다.

우선 최근 소스의 예제에서 udp 서버 example을 돌려보려 하였으나,

from gevent.server import DatagramServer
에서와 같이 gevent.server가 DatagramServer를 가지고 있지 않았습니다.
최근 개발 버전에 들어가 있는듯 하였습니다.

그래서 찾은 것은,


상단의 udpserver.py 파일 이름 대신,
dgram_server.py 라고 저장합니다.

그리고 하단의 udpserver_run.py 를 저장합니다.
그리고 모든 주소에서 UDP 패킷을 받기 위하여

udp_sock.bind(('192.168.1.228', 6000))
대신
udp_sock.bind(('0.0.0.0', 514))
모든 호스트에서 514번 포트를 봅니다.

물론 gevnet 패키지는 설치되어 있다고 가정합니다.

그러면 이제는 scapy를 이용하여,
 514번 UDP로 무언가를 보내어
잘 받는가를 살펴봅니다.

다른 우분투 호스트에 들어가서,

$ sudo apt-get install python-scapy

로 scapy 모듈을 설치한 상태에서,

$ sudo scapy
[sudo] password for future: 
INFO: Can't import python gnuplot wrapper . Won't be able to plot.
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
WARNING: No route found for IPv6 destination :: (no default route?)
Welcome to Scapy (2.2.0)
>>> 

와 같이 실행되면 잘 scapy 준비가 된 상태입니다.

우선, 위의 UDP 서버의 ip 주소가 10.31.80.80 이고,
scapy를 돌릴 서버의 ip 주소가 10.31.100.100 인 상태에서,

UDP 서버의 다른 터미널에서,

$ sudo tcpdump -nn -ieth1 icmp
라고 tcpdump로 ICMP 를 보고 있도록 합니다.

또한  scapy 에서는,

>>> p=IP()/ICMP()
>>> p.show()
###[ IP ]###
  version= 4
  ihl= None
  tos= 0x0
  len= None
  id= 1
  flags= 
  frag= 0
  ttl= 64
  proto= icmp
  chksum= None
  src= 127.0.0.1
  dst= 127.0.0.1
  \options\
###[ ICMP ]###
     type= echo-request
     code= 0
     chksum= None
     id= 0x0
     seq= 0x0

와 같이 디폴트 IP()/ICMP() 를 만들어 봅니다.

>>> p.src='10.31.1.2'
>>> p.dst='10.31.80.80'
>>> p.show()
###[ IP ]###
  version= 4
  ihl= None
  tos= 0x0
  len= None
  id= 1
  flags= 
  frag= 0
  ttl= 64
  proto= icmp
  chksum= None
  src= 10.31.1.2
  dst= 10.31.80.80
  \options\
###[ ICMP ]###
     type= echo-request
     code= 0
     chksum= None
     id= 0x0
     seq= 0x0

이렇게 src와 dst IP를 수정한 다음,

>>> send(p)
.
Sent 1 packets.

를 보내면,
tcpdump는

14:19:48.349403 IP 10.31.1.2 > 10.31.80.80: ICMP echo request, id 0, seq 0, length 8

와 같은 결과를 나타냅니다.

또한 아까 만들어 놓았던, udp 서버를 다음과 같이

$ sudo python udpserver_run.py

을 돌려 놓습니다.


또한 scapy 쪽에서는

>>> u=IP(src='10.31.100.200',dst='10.31.80.80')/UDP(sport=[20000,20001,20002],dport=514)/'Hello?'
>>> u.show()
###[ IP ]###
  version= 4
  ihl= None
  tos= 0x0
  len= None
  id= 1
  flags= 
  frag= 0
  ttl= 64
  proto= udp
  chksum= None
  src= 10.31.100.200
  dst= 10.31.80.80
  \options\
###[ UDP ]###
     sport= ['20000', '20001', '20002']
     dport= syslog
     len= None
     chksum= None
###[ Raw ]###
        load= 'Hello?'
>>> send(u)
...
Sent 3 packets.

이렇게 만들어 보내면,

udp 샘플 서버는,

New message <Hello?>:('10.31.100.200', 20000)
New message <Hello?>:('10.31.100.200', 20001)
New message <Hello?>:('10.31.100.200', 20002)

와 같은 결과를 보여줍니다.


어느 분께는 도움이 되셨기를...

핑백

  • 지훈현서 : [Python] gevent 와 ZeroMQ 혼용하기 2014-09-15 15:36:39 #

    ... 예전에 gevent를 이용한 UdpServer 를 구성해 본 적이 있습니다. 파이썬에서는 GIL 때문에 발생할 수 있는 쓰레드 Concurrency를마치 JavaScript의 비동기 함수 호출처 ... more

덧글

댓글 입력 영역

구글애드텍스트