본문 바로가기
프로그래밍/파이썬

GUI 멀티 채팅 프로그램 (TKinter, Thread, Socket)

by 의탕 2020. 12. 17.

수업시간에 배운 내용들을 토대로 하여 작은 프로그램을 하나 만들어 보았다.

 

프로그램은 GUI 멀티 채팅 프로그램이며, Tkinter와 스레드, 소켓 라이브러리를 활용하여 구현했다.

 

위 세 라이브러리를 실제로 사용한 것은 이번이 처음이지만, 프로그램을 완성시키기 위해 이것 저것 검색해보고 분석하다보니 금방 적응할 수 있었다.

 

 

소스를 살펴보자~!

 

 

<server>

import socket, threading

class Room:  # 채팅방 클래스.
    def __init__(self):
        self.clients = []
        self.allChat=None

    def addClient(self, c):  # c: 텔레마케터 . 클라이언트 1명씩 전담하는 쓰레드
        self.clients.append(c)

    def delClient(self, c):
        self.clients.remove(c)

    def sendMsgAll(self, msg):  # 채팅방에 있는 모든 사람한테 메시지 전송
        for i in self.clients:
            print(i)
            i.sendMsg(msg)


class ChatClient:  # 텔레마케터
    def __init__(self, r, soc):
        self.room = r  # 채팅방. Room 객체
        self.id = None  # 사용자 id
        self.soc = soc  # 사용자와 1:1 통신할 소켓

    def readMsg(self):
        self.id = self.soc.recv(1024).decode()
        msg = self.id + '님이 입장하셨습니다'
        self.room.sendMsgAll(msg)

        while True:
            msg = self.soc.recv(1024).decode()  # 사용자가 전송한 메시지 읽음
            if msg == '/stop':  # 종료 메시지이면 루프 종료
                self.soc.sendall(msg)  # 이 메시지를 보낸 한명에게만 전송
                self.room.delClient(self)
                break
            msg = self.id+': '+ msg
            self.room.sendMsgAll(msg)  # 모든 사용자에 메시지 전송
        self.room.sendMsgAll(self.id + '님이 퇴장하셨습니다.')

    def sendMsg(self, msg):
        print(type(msg))
        self.soc.sendall(msg.encode(encoding='utf-8'))


class ChatServer:
    ip = 'localhost'  # or 본인 ip or 127.0.0.1
    port = 9999

    def __init__(self):
        self.server_soc = None  # 서버 소켓(대문)
        self.room = Room()

    def open(self):
        self.server_soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_soc.bind((ChatServer.ip, ChatServer.port))
        self.server_soc.listen()

    def run(self):
        self.open()
        print('서버 시작11')

        while True:
            client_soc, addr = self.server_soc.accept()
            print(addr, '접속')
            c = ChatClient(self.room, client_soc)
            self.room.addClient(c)
            print('클라:',self.room.clients)
            th = threading.Thread(target=c.readMsg)
            th.start()

        self.server_soc.close()


def main():
    cs = ChatServer()
    cs.run()


main()

 

<client>

import threading
import socket
import tkinter as tk


class UiChatClient:
    # class 변수 / static 변수 : 모든 객체가 공유
    ip = 'localhost'
    port = 9999

    def __init__(self):
        self.conn_soc = None  # 서버와 연결된 소켓
        self.win = None
        self.chatCont = None
        self.myChat = None
        self.sendBtn = None
        self.allChat =''

    def conn(self):
        self.conn_soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.conn_soc.connect((UiChatClient.ip, UiChatClient.port))

    def setWindow(self):
        self.win = tk.Tk()
        self.win.title('채팅프로그램')
        self.win.geometry('400x500+100+100')
        self.chatCont = tk.Label(self.win, width=50, height=30, text='dd')
        self.myChat = tk.Entry(self.win, width=40)
        self.sendBtn = tk.Button(self.win, width=10, text='전송')

        self.chatCont.grid(row=0, column=0, columnspan=2)
        self.myChat.grid(row=1, column=0, padx=10)
        self.sendBtn.grid(row=1, column=1)

        self.myChat.bind('<Return>', self.sendMsg)


    def sendMsg(self, e):  # 키보드 입력 받아 상대방에게 메시지 전송
        msg = self.myChat.get()
        self.myChat.delete(0, tk.END)
        self.myChat.config(text='')
        print(type(msg))
        msg = msg.encode(encoding='utf-8')
        print(self.conn_soc)
        self.conn_soc.sendall(msg)
        print('전송')

    def recvMsg(self):  # 상대방이 보낸 메시지 읽어서 화면에 출력
        print('리드')
        while True:
            print('리드')
            msg = self.conn_soc.recv(1024)
            print(msg)
            msg = msg.decode()+'\n'
            self.allChat += msg
            print(',:', self.allChat)

            self.chatCont.config(text=self.allChat)
            # if msg == '/stop':
            #     self.close()
            #     break

    def run(self):
        self.conn()
        self.setWindow()

        th2 = threading.Thread(target=self.recvMsg)
        th2.start()
        self.win.mainloop()

    def close(self):
        self.conn_soc.close()
        print('종료되었습니다')


def main():
    conn = UiChatClient()
    conn.run()


main()

<실행 화면>

3개의 클라이언트를 띄워놓고 실행하였다.

 디자인적으로는 미숙하지만 기능상 전혀 문제가 없다ㅎㅎ

 

 

 

<깨달음>

각각의 라이브러리들이 조각조각 모여 퍼즐처럼 전체 프로그램을 완성시키는 모습에, 좀 더 규모가 큰 실 운영 프로그램은 더욱 많은 라이브러리를 필요로 할 것이라는 생각을 하였다. 그러므로 다양한 라이브러리를 접하고 익혀야 겠다는 생각을 하였다.

'프로그래밍 > 파이썬' 카테고리의 다른 글

파이썬 스레드 (Thread)  (0) 2020.12.17
계산기 프로그램 TKinter  (0) 2020.12.17
TKinter 기본 (파이썬 GUI)  (0) 2020.12.17
파이썬 소켓(TCP)  (0) 2020.12.15
제어문 - IF  (0) 2020.11.05

댓글