빅데이터 프로그래밍/Python

[Python] 16. [Network] socketserver 네트워크 프레임워크, Echo Server 2, 파일 송수신

밍글링글링 2017. 8. 2.
728x90
1. 계속 실행되는 Echo 서버의 제작
- socketserver.BaseRequestHandler class를 상속받아 구현
 
 
[실행 화면] 
/ws_python/oop/network>python EchoServer2.py
▷ network.EchoServer2.py
-----------------------------------------------------------------------------------
# -*- coding: utf-8 -*-

import socketserver

HOST = ''
PORT = 9009 # 0 ~ 65535, 일반적으로 1000번이상 사용하면 충돌이 없음.

# socketserver.BaseRequestHandler 상속받아 구현
class MyTcpHandler(socketserver.BaseRequestHandler):
    # 이 클래스는 서버 하나당 단한번 초기화됩니다.
    # handle() 메소드에 클라이언트 연결 처리를 위한 로직을 구현합니다.
    # 접속자가 발생하면 자동 호출됨, Call Back 메소드.
    def handle(self):
        print('▷ [%s] 연결됨' %self.client_address[0]) # 연결된 IP 출력 

        try:
            while True:
                self.data = self.request.recv(1024)  # 수신 대기
                if self.data.decode() == '/exit':
                    print('▷ [%s] 사용자에 의해 중단' %self.client_address[0])
                    return  # while문 종료

                print('[%s]' %self.data.decode())  # 수신 메시지 출력
                self.request.sendall(self.data)      # 현재 접속자에게 전송
        except Exception as e:
            print(e)

def runServer():
    print('▷ 에코 서버를 시작합니다.')
    print('▷ 에코 서버를 끝내려면 접속된 사용자를 종료후 Ctrl-C를 누르세요.')

    try:
        server = socketserver.TCPServer((HOST, PORT), MyTcpHandler)       
        server.serve_forever() # Ctrl + C, server.shutdown() 호출시까지 계속 실행
    except KeyboardInterrupt:
        print('▷ 에코 서버를 종료합니다.')
      
runServer()

    
-----------------------------------------------------------------------------------
 
2. Echo client의 제작

 

[실행 화면]
/ws_python/oop/network>python EchoClient2.py 172.16.7.100
▷ network.EchoClient2.py
-----------------------------------------------------------------------------------
# -*- coding: utf-8 -*-

import socket, sys

HOST = sys.argv[1]  # localhost, 콘솔 입력, 첫번째 전달 값 IP
PORT = 9009          # 서버의 포트

# sock 객체를 생성하며 자동 Close
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    sock.connect((HOST, PORT)) # 서버로 접속
    
    while True:
        msg = input('메시지 입력: ')
        if msg == '/exit':
            sock.sendall(msg.encode()) # /exit 전송
            break  # while 문 종료

        sock.sendall(msg.encode()) # 서버로 메시지 전송
        data = sock.recv(1024)       # 수신 대기
        print('에코 서버로부터 받은 데이터 [%s]' %data.decode())

print('클라이언트 종료')

  
-----------------------------------------------------------------------------------
 

 

02. socketserver 네트워크 프레임워크를 이용한 파일 송수신
 
1. File 서버의 제작
- socketserver.BaseRequestHandler class를 상속받아 구현
 
 
[실행 화면] 
/ws_python/oop/network>python FileServer1.py
▷ network.FileServer1.py
-----------------------------------------------------------------------------------
# -*- coding: utf-8 -*-

import sys
import socketserver
from os.path import exists

class MyTcpHandler(socketserver.BaseRequestHandler):
    # 접속자 발생시 호출
    def handle(self):
        data_transferred = 0
        print('[%s] 연결됨' %self.client_address[0])
        filename = self.request.recv(1024) # 전송할 파일명 수신
        
        if filename.decode() == '/exit':
            print('▷ [%s] 사용자에 의해 중단' %self.client_address[0])
            # sys.exit()  # 서버 종료       
        
        # 파일 접근시 절대 경로가 필요함으로 지정된 경로 조합                
        filename = 'C:/201705_python/swiss/'  + filename.decode()
        print('--> filename: ' + filename)
        
        if not exists(filename): # 파일이 존재하는지 검사
            return # 존재하지 않으면 처리 중지

        print('파일 [%s] 전송 시작...' %filename) 
        with open(filename, 'rb') as f:  # read binary          
            try:
                data = f.read(1024)  # 1 KB 읽기
                # 파일이 전송 종료해야 while문 끝남.
                while data: # 0이 아니면 계속 순환, 파일에서 읽은 데이터수가 있다면
                    # self.request: 접속된 Client, 읽은 데이터 전송
                    # 전송한 바이트 수을 누적
                    data_transferred = data_transferred + self.request.send(data)
                    data = f.read(1024) # 파일에서 1 KB 읽기
            except Exception as e:
                print(e)

            print('전송완료[%s], 전송량[%d]' %(filename, data_transferred))
        
def runServer(host, port):
    print('▷ 파일 서버를 시작합니다.')
    print('▷ 파일 서버를 끝내려면 Ctrl-C를 누르세요.')

    try:
        server = socketserver.TCPServer((host, port), MyTcpHandler)       
        server.serve_forever()
    except KeyboardInterrupt:
        print('▷ 파일 서버를 종료합니다.')

''' 
F:
CD 201704_python/ws_python/oop/network
python FileServer1.py 172.16.7.100 9009
'''
runServer(sys.argv[1], int(sys.argv[2])) 

  

-----------------------------------------------------------------------------------
 

 

2. File client의 제작
- C:/201705_python/download 폴더를 미리 생성합니다.

 

[실행 화면]
/ws_python/oop/network>python FileClient1.py
 
▷ network.FileClient1.py
-----------------------------------------------------------------------------------
# -*- coding: utf-8 -*-

import sys, socket

def getFileFromServer(host, port, filename):
    data_transferred = 0
    
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect((host, port)) # 서버 연결
        sock.sendall(filename.encode()) # 파일명 전송, 서버 종료: /exit

        data = sock.recv(1024) # 파일 수신
        if not data: # 읽은 데이터 없는 경우
            print('파일[%s]: 서버에 존재하지 않거나 전송중 오류발생' %filename)
            return 

        # 기록을 위해 보낸 파일명으로 쓰기 모드로 열기 
        with open('C:/201705_python/download/'+filename, 'wb') as f:
            try:
                while data: # 수신된 데이터가 있으면 계속 실행
                    f.write(data) # 1KB 기록
                    data_transferred = data_transferred + len(data) # 수신받은 데이터 산출
                    data = sock.recv(1024) # 새로운 1 KB 데이터 수신
            except Exception as e:
                print(e)

            print('파일 [%s] 전송종료. 전송량 [%d]' %(filename, data_transferred))
            # 파일 전송 받으면 네트워크 종료 
'''
F:
CD 201704_python/ws_python/oop/network
python FileClient1.py 172.16.7.100 9009
'''
while True:  # 무한 루틴
    print('종료는 \'/exit\' 입니다.');
    filename = input('다운로드 받을 파일이름을 입력하세요: ')

    if filename == '/exit':
        sys.exit()
        
    # 접속 시도              
    getFileFromServer(sys.argv[1], int(sys.argv[2]), filename) 
   


-----------------------------------------------------------------------------------
 

728x90

댓글