본문 바로가기
파이썬

중계서버-멀티채팅(GUI버전)

by 가오가이거 2020. 12. 17.
#클라이언트 코드
import socket, threading
import tkinter as tk

#전역변수
client_socket = None #서버와 1:1 통신할 소켓
label = None #레이블, 채팅내용
Msg = None #입력박스
root = None

def send(e): #이벤트 핸들러함수. 엔트리 엔터입력시 호출.
    global client_socket
    
    msg = Msg.get()#입력박스에 입력한 텍스트 읽어옴
    client_socket.sendall(msg.encode())
    Msg.delete(0, tk.END)

def th_read():
    global client_socket
    while True:
        data = client_socket.recv(1024)
        msg = data.decode()
        #print(msg)
        
        label.configure(text=label.cget('text')+'\n'+msg)
        if msg=='/stop':
            break
        
    print('서버 메시지 출력 쓰레드 종료')
    
def ui_init():
    global label
    global Msg
    global root

    root = tk.Tk() #윈도우 창

    root.title('chatting room')#윈도우 제목창 타이틀 출력
    root.geometry("400x400")#윈도우 가로 세로 길이
    frm = tk.Frame(root)    #윈도우에 프레임을 생성. 화면분할용도

    #레이블 생성
    label = tk.Label(root, text = '', relief = 'groove', borderwidth = 1, padx = 400, pady = 150)
    #입력박스 생성
    Msg = tk.Entry(root,width = 100)
    Msg.bind('<Return>', send)
    #버튼 생성
    #btn = tk.Button(root, text="send", command = send)

    #위젯들을 프레임에 부착
    Msg.pack()
    frm.pack()
    label.pack()   
    #btn.pack()
    
    

def main():
    global root
    global client_socket
    
    HOST = 'localhost'
    PORT = 9999

    #통신할 소켓 오픈 
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    #서버에 연결요청. server ip, port
    client_socket.connect((HOST, PORT))

    ui_init()
    
    t2 = threading.Thread(target=th_read, args=())
    t2.start()

    root.mainloop()
    #client_socket.close()

main()

 

 

 

 

#서버 코드
import socket, threading
soc_list=[] #채팅방. 연결된 클라이언트 소켓

def client(soc, addr):
    soc_list.append(soc) #방금 접속한 클라이언트 소켓을 리스트에 담음
    
    while True:
        data = soc.recv(1024)
        msg = data.decode()
        if msg=='/stop':
            soc.sendall(data)#본인한테 /stop 전송
            soc_list.remove(soc)
            msg = str(addr)+' 님이 퇴장하셨습니다.'
            for s in soc_list:
                s.sendall(msg.encode())
            break
        else:
            print('Received from', addr, msg)
            msg = str(addr)+' : '+msg
            for s in soc_list:
                s.sendall(msg.encode())
    soc.close()
    print(addr, '퇴장')

def main():
    HOST = 'localhost'  #server ip
    PORT = 9999         #server port

    #server socket open. socket.AF_INET:주소체계(IPV4), socket.SOCK_STREAM:tcp 
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    #포트 여러번 바인드하면 발생하는 에러 방지
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    #바인드:오픈한 소켓에 IP와 PORT 할당
    server_socket.bind((HOST, PORT))

    #이제 accept할 수 있음을 알림
    server_socket.listen()

    print('server start')

    #accept로 client의 접속을 기다리다 요청시 처리.
    #client와 1:1통신할 작은 소켓과 연결된 상대방의 주소 반환
    while True:
        client_socket, addr = server_socket.accept()
        print('Connected by', addr)
        t = threading.Thread(target=client, args=(client_socket,addr))
        t.start()
  
    server_socket.close()

main()