[[TableOfContents]] Python 에서는 기본적으로 Socket Library 를 제공해준다. 그리고 async i/o 모듈인 medusa 가 이제는 기본으로 제공된다. 만일 winsock 을 쓰고 싶다면 windows extension libary 들을 설치해주면 된다. === TCP Socket === ==== Client ==== {{{~cpp from socket import * host = "localhost" port = 9000 addr = (host, port) sock = socket(AF_INET, SOCK_STREAM) sock.connect(addr) sock.send("TEST") sock.close }}} ==== Server ==== {{{~cpp from socket import * port = 9010 bufsize = 1024 maximumConnection = 5 sock = socket(AF_INET, SOCK_STREAM) sock.bind(("localhost",port)) sock.listen(maximumConnection) while 1: newsock, client_addr = sock.accept() print "Client connected:",client_addr data = newsock.recv(bufsize) print data }}} === UDP Socket === {{{~cpp #server.py from socket import * host = "localhost" port = 1005 buf = 1024 addr = (host, port) UDPSock = socket(AF_INET, SOCK_DGRAM) UDPSock.bind(addr) while 1: data, addr = UDPSock.recvfrom(buf) if not data: print "Client has exited!" break else: print "\n Received message '", data,"'" UDPSock.close() #client.py from socket import * host = "localhost" port = 1005 buf = 1024 addr = (host, port) UDPSock = socket(AF_INET, SOCK_DGRAM) def_msg = "==Enter message to send to server==" print "\n", def_msg while(1): data = raw_input('>> ') if not data: break else: if(UDPSock.sendto(data,addr)): print "Sending message '",data,"'..." UDPSock.close() }}} === normal socket === 역시. 아주아주 간단한 예제.~ {{{~cpp from socket import * from threading import * class ListenThread(Thread): def __init__(self, aServer): Thread.__init__(self) self.server=aServer def run(self): clientConnection, address = self.server.listenSock.accept() print address clientConnection.send("hahaharn") clientConnection.close() self.server.listenSock.close() class Server: def serve(self, aPort): self.listenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP) here=('',aPort) self.listenSock.bind(here) self.listenSock.listen(5) listenThread=ListenThread(self) listenThread.start() if __name__=="__main__": server = Server() server.serve(30002) }}} 또는, 기본 모듈로 있는 SocketServer 모듈을 사용할 수 있다. 다음은 간단한 예제. {{{~cpp from SocketServer import * HOST = ('', 7000) ClientList = [] ClientConnections = [] class MyServer (BaseRequestHandler): def broadcast (self, msg): for conn in ClientConnections: conn.send (msg) def handle(self): conn = self.request if conn: peername = conn.getpeername () ClientList.append (peername) ClientConnections.append (conn) print "Requested by ", peername try: cmd = raw_input (">> ") while cmd: if cmd == 'ls': print "== Connected Client Lists ==" print ClientList self.broadcast ("ls command inputed...n") cmd = raw_input (">> ") except: print "Socket Error occured.." return if __name__ == '__main__': my_server = ThreadingTCPServer (HOST, MyServer) my_server.serve_forever () }}} === Medusa === Medusa 는 내부적으로 select / poll 를 이용, 비동기 소켓부분을 구현한다. 소켓 이벤트들 처리에 대한 인터페이스가 아주 깔끔. 참 마음에 든다. MFC 의 CSocket 를 사용하는 스타일로 프로그래밍을 할 수 있는데, Python 이기에 코드가 더 깔끔. 그리고 Windows/Linux 양쪽 다 가능. 다음은 화일 보내는 부분과 관련한 간단한 예제. {{{~cpp import asyncore import socket from threading import * import os import os.path class FileSendChannel(asyncore.dispatcher, Thread): def __init__(self, aConnection, anAddress): asyncore.dispatcher.__init__(self, aConnection) Thread.__init__(self) print "file send channel create." print "address :", anAddress self.address = anAddress def run(self): print "file send channel start." self.fileSendMain() def writable(self): return not self.connected def handle_read(self): bufferSize=8192 data = self.recv(bufferSize) print "data :", data def handle_close(self): self.close() print "closed channel..." def getFileSize(self, aFileName): return os.path.getsize(aFileName) def fileSendMain(self): aFileName='f:/sample.jpg' fileSize=self.getFileSize(aFileName) print "file size : ", fileSize f = open(aFileName, "rb") print "file opened.." currentReaded=0 while currentReaded < fileSize: data = f.read(1024) #currentReaded = f.tell() sended = self.send(data) currentReaded+=sended f.seek(currentReaded, 0) print "current : %d, sended : %d"%(currentReaded, sended) f.close() print "send completed..." self.close() class FileSendServer(asyncore.dispatcher): def __init__(self): asyncore.dispatcher.__init__(self) def initialize(self): self.create_socket(socket.AF_INET, socket.SOCK_STREAM) def handle_accept(self): connection, address = self.accept() channel = FileSendChannel(connection, address) channel.start() def handle_close(self): pass def handle_read(self): pass def handle_write(self): pass def serve(self, aPort): self.initialize() here = ('', aPort) self.bind(here) self.listen(5) if __name__=='__main__': server = FileSendServer() server.serve(30002) asyncore.loop() }}} 다음은 화일 받는 부분과 관련한 간단한 예제. {{{~cpp import asyncore import socket class FileReceiveChannel(asyncore.dispatcher): def __init__(self): asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.received = 0 self.f=open("f://output1.jpg","wb") def handle_connect(self): print "connected..." def writable(self): return not self.connected def handle_write(self): pass def handle_read(self): data = self.recv(8192) self.received += len(data) print "received : %d, %d"%(len(data), self.received) self.f.write(data) def handle_close(self): print "closed..." self.f.close() self.close() def main(self, aHost, aPort): self.connect((aHost, aPort)) if __name__=="__main__": client=FileReceiveChannel() host = "localhost" port = 30002 client.main(host, port) asyncore.loop() }}} 여기서 recv 메소드는 데이터가 들어온 만큼 받는다. (즉, 버퍼사이즈만큼 데이터가 들어올때까지 기다리지 않는다.) === 참고 사이트 === * [http://gnosis.cx/publish/programming/sockets.html] ---- [Python]