본문 바로가기

PYTHON-BACK

#파이썬 기초 16일차

728x90

2.5 채팅 서비스 만들기

 

2.5.1 채팅 서버 만들기

chatserver.py

import socketserver
import threading

HOST = ''
PORT = 9009
lock = threading.Lock()

class UserManager:
    def __init__(self):
        self.users = {}

    def addUser(self, username, conn, addr):
        if username in self.users:
            conn.send('이미 등록된 사용자입니다.\n'.encode())
            return None

        # 새로운 사용자를 등록함
        lock.acquire()
        self.users[username] = (conn, addr)
        lock.release()

        self.sendMessageToAll('[%s]님이 입장했습니다.' % username)
        print('+++ 대화 참여자 수 [%d]' % len(self.users))

        return username

    def removeUser(self, username):  # 중간에 채팅방에서 나가는 사람
        if username not in self.users:  # 있으면 지우고 없으면 못지움
            return

        lock.acquire()  # 락 풀기
        del self.users[username]  # 방금 입력받은 유저네임을 키로 해서 지움
        lock.release()  # 다시 락 걸기

        self.sendMessageToAll('[%s]님이 퇴장했습니다.' % username)
        print('--- 대화 참여자 수 [%d]' % len(self.users))

    def messageHandler(self, username, msg):  # 메시지 어떻게 만들어 사용할 것인지
        if msg[0] != '/':
            self.sendMessageToAll('[%s] %s' % (username, msg))
            return

        if msg.strip() == '/quit':
            self.removeUser(username)
            return -1

    def sendMessageToAll(self, msg):
        for conn, addr in self.users.values():
            conn.send(msg.encode())

class MyTcpHandler(socketserver.BaseRequestHandler):
    userman = UserManager()

    def handle(self):
        print('[%s] 연결됨' % self.client_address[0])  # 참조 받았언 BaseRequestHandler 안에 들어있음

        try:
            username = self.registerUsername()
            msg = self.request.recv(1024)

            while msg:
                print(msg.decode())

                if self.userman.messageHandler(username, msg.decode()) == -1:
                    self.request.close()
                    break

                msg = self.request.recv(1024)

        except Exception as e:
            print(e)

        print('[%s] 접속종료' % self.client_address[0])
        self.userman.removeUser(username)

    def registerUsername(self):
        while True:
            self.request.send('로그인ID:'.encode())
            username = self.request.recv(1024)
            username = username.decode().strip()
           
            if self.userman.addUser(username, self.request, self.client_address):
                return username

class ChatingServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

def runServer():
    print('+++ 채팅 서버를 시작합니다.')
    print('+++ 채팅 서버를 끝내려면 Ctrl-C를 누르세요.')

    try:
        server = ChatingServer((HOST, PORT), MyTcpHandler)
        server.serve_forever()
    except KeyboardInterrupt:
        print('--- 채팅 서버를 종료합니다.')
        server.shutdown()
        server.server_close()

runServer()

 

chatclient.py

import socket
from threading import Thread

HOST ='localhost'
PORT = 9009

def rcvMsg(sock): # 메시지를 받아들이는 부분
    while True:
        try:
            data = sock.recv(1024)
            if not data:
                break
            print(data.decode())

        except:
            pass

def runChat():
   with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
      sock.connect((HOST, PORT))
      t = Thread(target=rcvMsg, args=(sock,))
      t.daemon = True
      t.start()

      while True:
         msg = input()
         if msg == '/quit':
            sock.send(msg.encode())
            break

         sock.send(msg.encode())

runChat()

2.6 파일 전송 프로그램 만들기

 

2.6.1 파일 송신 프로그램

import socketserver
from os.path import exists

HOST = ''
PORT = 9009

class MyTcpHandler(socketserver.BaseRequestHandler):
   def handle(self):
      data_transferred = 0
      print('[%s] 연결됨' %self.client_address[0])
      filename = self.request.recv(1024)
      filename = filename.decode()

      if not exists(filename):
         return

      print('파일 [%s] 전송 시작...' %filename)
      with open(filename, 'rb') as f:
         try:
            data = f.read(1024)
            while data:
               data_transferred += self.request.send(data)
               data = f.read(1024)
         except Exception as e:
            print(e)

      print('전송완료[%s], 전송량[%d]' %(filename, data_transferred))

def runServer():
   print('+++ 파일 서버를 시작합니다.')
   print('+++ 파일 서버를 끝내려면 Ctrl-C를 누르세요.')

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

runServer()

 

2.6.2 파일 수신 프로그램

import socket

HOST = 'localhost'
PORT = 9009

def getFileFromServer(filename):
   data_transferred = 0

   with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
      sock.connect((HOST, PORT))
      sock.sendall(filename.encode())

      data = sock.recv(1024)
      if not data:
         print('파일[%s]: 서버에 존재하지 않거나 전송중 오류발생' %filename)
         return

      with open('download/'+filename, 'wb') as f:
         try:
            while data:
               f.write(data)
               data_transferred += len(data)
               data = sock.recv(1024)
         except Exception as e:
            print(e)

   print('파일 [%s] 전송종료. 전송량 [%d]' %(filename, data_transferred))

filename = input('다운로드 받을 파일이름을 입력하세요: ')
getFileFromServer(filename)
728x90

'PYTHON-BACK' 카테고리의 다른 글

#파이썬 도서관 출납 시스템_17일차  (3) 2024.07.23
#파이썬 도서관 출납 시스템_16일차  (1) 2024.07.22
#파이썬 기초 15일차  (0) 2024.07.19
#파이썬 기초 14일차  (0) 2024.07.18
#파이썬 기초 13일차  (0) 2024.07.17