Python 에서는 기본적으로 Socket Library 를 제공해준다. 그리고 async i/o 모듈인 medusa 가 이제는 기본으로 제공된다.

만일 winsock 을 쓰고 싶다면 windows extension libary 들을 설치해주면 된다.

1. TCP Socket

1.1. 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

1.2. 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

2. 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()

3. 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 ()

4. 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 메소드는 데이터가 들어온 만큼 받는다. (즉, 버퍼사이즈만큼 데이터가 들어올때까지 기다리지 않는다.)

5. 참고 사이트

Retrieved from http://wiki.zeropage.org/wiki.php/PythonNetworkProgramming
last modified 2021-02-07 05:24:08