ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [python] 채팅 프로그램 만들기 (1)
    카테고리 없음 2022. 11. 20. 01:03

    오랜만에 올리는 글.. 이게 몇달 만이지...ㅎㅎ 앞으로는 좀 더 성실히 올리도록 하겠습니다! 글을 안 올릴동안 다양한걸 만들고 공부했는데요. 앞으로 만들고 공부했던 것들을 모두 차근차근 올려보도록 하겠습니다. 

    오늘은 좀 더 블로그에서 소통을 많이 하고자 채팅 프로그램을 만들어보도록 하겠습니다. 그래서 서로 다른 컴퓨터끼리 소통을 위해 socket이라는 라이브러리를 사용하여 소켓 통신으로 프로그램을 제작해보았습니다.  

    먼저, 소켓 통신에 대해 간단하게 설명하자면, 네트워크를 통해 서로 통신하며 데이터를 주고받는 것 입니다. 

     

    채팅 프로그램을 구현하기 위해서는 두 개의 프로그램을 완성시켜야 합니다. 

    첫 번째로 사용자로부터 데이터를 받고 처리하여 데이터를 다시 사용자에게 전송하는 'server'가 필요합니다.

    다음으로 서버에 접속하여 서버에게 데이터를 전송하고 데이터를 받으며 출력하는 'client'가 필요합니다.  

     

    이번 글에서는 서버를 먼저 만들어보도록 하겠습니다. 

    import socket
    import select
    
    HEADER_LENGTH = 10
    IP = "127.0.0.1"
    PORT = 1234
    
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
    server_socket.bind((IP, PORT))
    server_socket.listen()
    
    sockets_list = [server_socket]
    
    clients = {}
    
    def receive_message(client_socket):
        try:
            message_header = client_socket.recv(HEADER_LENGTH)
    
            if not len(message_header):
                return False
            
            message_lenth = int(message_header.decode().strip())
            return {"header" : message_header, "data" : client_socket.recv(message_lenth)}
    
        except:
            return False
    
    while True:
        read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)
        
        for notified_socket in read_sockets:
            if notified_socket == server_socket:
                client_socket, client_address = server_socket.accept()
    
                user = receive_message(client_socket)
                if user is False:
                    continue
    
                sockets_list.append(client_socket)
    
                clients[client_socket] = user
                
                print(f"Aceepeted new connection from {client_address[0]} : {client_address[1]} username : {user['data'].decode()}")
    
            else:
                message = receive_message(notified_socket)
    
                if message is False:
                    print(f"Closed connection from {clients[notified_socket]['data'].decode('utf-8')}")
                    sockets_list.remove(notified_socket)
                    del clients[notified_socket]
                    continue
                
                user = clients[notified_socket]
                print(f"Received message from {user['data'].decode()}:{message['data'].decode()}")
    
                for client_socket in clients:
                    if client_socket != notified_socket:
                        client_socket.send(user['header']+user['data']+message['header']+message['data'])
    
        for notified_socket in exception_sockets:
            sockets_list.remove(notified_socket)
            del clients[notified_socket]

    코드는 다음과 같습니다. 

    처음으로 IP, PORT를 정의해줍니다. IP에 있는 127.0.0.1은 자기자신을 의미하는 IP주소 입니다. 다른 컴퓨터와 서로 통신하기 위해서는 IP주소를 바꿔줘야합니다. 먼저 내 컴퓨터의 IP를 확인하는 방법을 설명하겠습니다. 

    먼저, cmd 창을 켜줍니다. (윈도우+R 입력 후 cmd를 입력하고 앤터를 치면 빠르게 킬 수 있습니다.

    다음으로 ipconfig라고 입력합니다. 그러면 잘 이해가 안되는 글과 숫자들이 뿅 나타납니다. 나타난 글 중에서 중간에서 좀 아래부분을 보면 IPv4 주소라고 쓰여져 있는 부분이 있고 그 뒤에 숫자가 있습니다. 그것이 이 컴퓨터의 IP주소입니다. 

    이 예시에서는 IP = '192.166.0.159'로 바꾸시면 다른 컴퓨터와의 소통이 가능해집니다. IP는 컴퓨터와 접속하는 인터넷마다 달라질 수 있음을 유의하시길 바랍니다. 

     

    다음으로 서버의 소켓을 정의합니다. 그리고 server_socket.listen()으로 다른 client의 접속이 있는지, 접속되어있는 client가 데이터를 전송했는지 확인합니다. 

    recive_message()는 다른 client로부터 메세지를 받습니다. 받은 메세지는 보낸 client와 함께 저장합니다. 소켓을 통해 전송할 때는 bytes 형태로 전송해야합니다. 그래서 전송 받을 때 데이터(메세지)의 형태 또한 bytes 형태일 것이므로 프로그램에서 사람들이 해석할 수 있는 형태로 바꿔줘야합니다. 전송받은 데이터가 message라면 message.decode() 또는 message.decode('utf-8')로 bytes 형태의 데이터를 문자열 형태로 바꿔줍니다. 이것을 decode라고 하고 이와 반대로 문자열을 bytes로 바꿔주는 것을 encode라고 합니다. 

     접속한 소켓들은 리스트 형태로 저장하여 데이터 송수신에 사용됩니다. 데이터를 받는다면 이를 decode하여 적절한 client에게 전송합니다. 예를 들어 사람1부터 사람3까지 있다면 사람1이 보낸 데이터는 사람1을 제외한 사람2, 사람3에게 전송해야합니다. 저장된 메세지와 보낸 client를 통해 보낸 client를 제외한 나머지 client에게 메세지를 전송합니다. 이떄 전송하는 메세지 또한 bytes형태여야 하기 때문에 decode의 반대인 encode를 해줍니다. encode 또한 decode와 비슷하게 보낼 데이터가 message라면 message.encode() 또는 message.encode('utf-8')로 bytes 형태로 바꿔줄 수 있습니다. 

     

    이렇게 서버를 만들어봤습니다. 

    다음 글에서는 서버에 접속할 client를 제작해보도록 하겠습니다. 

     

     

     

    참고 자료

    https://www.youtube.com/watch?v=CV7_stUWvBQ&t=1117s

Designed by Tistory.