관리 메뉴

개발자비행일지

파이썬 채팅, 다중 채팅, gui, 파일 전송 본문

▶ Python

파이썬 채팅, 다중 채팅, gui, 파일 전송

Cyber0946 2023. 7. 20. 18:55

먼저, 서버 측 코드를 작성하겠습니다. 

import socket
import threading
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QTextEdit, QLineEdit, QPushButton

class ChatWindow(QMainWindow):
    def __init__(self, host, port):
        super().__init__()

        self.host = host
        self.port = port
        self.username = None
        self.socket = None

        self.setWindowTitle("다중 채팅 시스템")
        self.setGeometry(100, 100, 500, 400)

        self.central_widget = QWidget(self)
        self.setCentralWidget(self.central_widget)

        self.layout = QVBoxLayout()
        self.central_widget.setLayout(self.layout)

        self.text_area = QTextEdit()
        self.text_area.setReadOnly(True)
        self.layout.addWidget(self.text_area)

        self.input_field = QLineEdit()
        self.input_field.returnPressed.connect(self.send_message)
        self.layout.addWidget(self.input_field)

        self.connect_to_server()

    def connect_to_server(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((self.host, self.port))

        self.username, ok = self.get_username()
        if not ok:
            self.close()

        self.socket.send(self.username.encode())

        receive_thread = threading.Thread(target=self.receive_messages)
        receive_thread.start()

    def get_username(self):
        username, ok = QInputDialog.getText(
            self,
            "사용자 이름 입력",
            "사용자 이름을 입력하세요:"
        )
        return username, ok

    def receive_messages(self):
        while True:
            try:
                message = self.socket.recv(1024).decode()
                self.text_area.append(message)
            except Exception as e:
                print(f"서버와의 연결이 끊어졌습니다: {str(e)}")
                self.socket.close()
                break

    def send_message(self):
        message = self.input_field.text()
        self.input_field.clear()
        self.socket.send(message.encode())
        if message == "!quit":
            self.socket.close()
            self.close()


if __name__ == "__main__":
    app = QApplication([])
    window = ChatWindow("127.0.0.1", 12345)
    window.show()
    app.exec_()

 

위의 코드는 다중 사용자 채팅 서버를 구현한 것입니다. 서버는 클라이언트의 연결을 받아들이고 관리하며, 클라이언트들 간의 메시지를 중개합니다. 새로운 클라이언트가 연결되면 클라이언트 소켓과 사용자 이름을 리스트에 추가하고, 새로운 스레드에서 해당 클라이언트를 처리합니다. 클라이언트가 메시지를 보내면 다른 클라이언트들에게 메시지를 전송하며, 클라이언트가 연결을 종료하면 클라이언트를 제거하고 소켓을 닫습니다.

다음으로, 클라이언트 측 코드를 작성하겠습니다. 다음은 간단한 클라이언트 코드입니다.

import socket
import threading

class ChatServer:
    def __init__(self, host, port):
        self.host = host
        self.port = port
        self.server_socket = None
        self.client_sockets = []
        self.client_usernames = []

    def start(self):
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.bind((self.host, self.port))
        self.server_socket.listen(5)

        print(f"서버가 {self.host}:{self.port}에서 실행 중입니다.")

        while True:
            client_socket, client_address = self.server_socket.accept()
            print(f"새로운 클라이언트가 연결되었습니다: {client_address}")

            username = client_socket.recv(1024).decode()
            self.client_sockets.append(client_socket)
            self.client_usernames.append(username)

            client_thread = threading.Thread(target=self.handle_client, args=(client_socket,))
            client_thread.start()

    def handle_client(self, client_socket):
        while True:
            try:
                message = client_socket.recv(1024).decode()
                if message:
                    self.broadcast(message, client_socket)
                else:
                    self.remove_client(client_socket)
                    break
            except Exception as e:
                print(f"클라이언트와의 연결이 끊어졌습니다: {str(e)}")
                self.remove_client(client_socket)
                break

    def broadcast(self, message, sender_socket):
        for client_socket in self.client_sockets:
            if client_socket != sender_socket:
                client_socket.send(message.encode())

    def remove_client(self, client_socket):
        if client_socket in self.client_sockets:
            index = self.client_sockets.index(client_socket)
            username = self.client_usernames[index]
            self.client_sockets.remove(client_socket)
            self.client_usernames.remove(username)
            client_socket.close()
            self.broadcast(f"{username}님이 나갔습니다.", client_socket)


if __name__ == "__main__":
    server = ChatServer("127.0.0.1", 12345)
    server.start()

 

 

위의 코드는 다중 사용자 채팅 클라이언트를 구현한 것입니다. 클라이언트는 서버에 연결한 후 사용자 이름을 입력하고, 서버로부터 메시지를 수신하고 메시지를 전송합니다. 클라이언트는 PyQt5를 사용하여 GUI를 구성합니다.

서버와 클라이언트 코드를 각각 실행하여 다중 사용자 간의 채팅을 테스트할 수 있습니다. 서버 코드를 먼저 실행한 다음, 여러 개의 클라이언트를 실행하여 서버에 연결하고 메시지를 주고받을 수 있습니다. 클라이언트들 간의 채팅은 서버를 통해 중개되며, 사용자 이름을 통해 구분됩니다.

서버와 클라이언트 코드를 함께 실행하면 다중 사용자가 사용하는 채팅 시스템이 구현되며, 클라이언트들은 서버를 통해 채팅을 주고받을 수 있습니다.