[개인프로젝트] tkinter로 GUI 입힌 tcp/ip 소켓 통신 프로그램 만들기

2020. 8. 7. 18:13·개인 프로젝트/토이 프로젝트
반응형

개인적으로 네트워크 관련 내용을 배울 기회를 갖게 되어, 배운 내용을 기반으로 채팅프로그램을 만들어보았습니다.

 

서버 소스 코드

''' 서버 예제
각 클라이어언트가 보낸 메세지를 서버에서 클라이언트 정보와 조합하여 각 클라이언트 채팅창에 띄워 보내 주는 역할 '''
import socket
from _thread import *
from tkinter import *

def threaded(client_socket, addr):
    global chat_log
    chat_log['state'] = 'normal'
    chat_log.insert("end", 'Connected by :'+ addr[0] + ':' + str(addr[1]) + '\n')
    chat_log['state'] = 'disabled'
    for c in c_list:
        c.sendall(('[System] ' + str(addr[1]) + ' 님이 접속하였습니다.').encode())
    while 1:
        try:
            data = client_socket.recv(1024)
            chat_log['state'] = 'normal'
            chat_log.insert("end", 'Received from ' + addr[0] + ' : ' + str(addr[1]) + ' :: ' + str(data.decode()) + '\n')
            chat_log['state'] = 'disabled'
            for c in c_list:
                c.sendall((str(addr[1]) + ' : ' + data.decode()).encode())
        except ConnectionResetError as e:
            c_list.remove(client_socket)
            for c in c_list:
                c.sendall(('[System] '+ str(addr[1]) + ' 님이 나갔습니다.').encode())
            chat_log['state'] = 'normal'
            chat_log.insert("end", 'Disconnected by ' + addr[0] + ':' + str(addr[1]) + '\n')
            chat_log['state'] = 'disabled'
            break
    client_socket.close()

def server_open():
    HOST = ip_entry.get(); PORT = int(port_entry.get())
    start_new_thread(make_server,(HOST,PORT))
    open_button['state'] = 'disabled'
    ip_entry['state'] = 'readonly'
    port_entry['state'] = 'readonly'

def server_close():
    exit()

def make_server(HOST, PORT):
    global server_socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 포트사용중이라 연결할 수 없다는 WinError 10048 에러를 해결하기 위해 필요합니다.
    # 서버 소켓의 SOL_SOCKET의 SO_REUSEADDR(이미 사용중인 포트에 대해서도 바인드 허용) 를 1(True)로 설정하는 것으로 이해
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    server_socket.bind((HOST, PORT))
    server_socket.listen()
    chat_log['state'] = 'normal'
    chat_log.insert("end", 'Server Start\n')
    chat_log['state'] = 'disabled'

    while 1:
        client_socket, addr = server_socket.accept()
        c_list.append(client_socket)
        start_new_thread(threaded, (c_list[-1], addr))

c_list = []
close = False
server_socket = None

s_root = Tk()
s_root.geometry('500x500')
s_root.title('Server')
s_root.resizable(False, False)

''' Top Menu '''
Label(s_root, text = 'Server IP : ').place(x=20, y=20)
Label(s_root, text = 'Port : ').place(x=250, y=20)
ip_entry = Entry(s_root, width=14, text = '127.0.0.1'); ip_entry.place(x=83, y=21)
ip_entry.insert(0,'127.0.0.1')
port_entry = Entry(s_root, width=5, text = '9999'); port_entry.place(x = 290, y=21)
port_entry.insert(0,'9999')
open_button = Button(s_root,text='Server Open', command=server_open); open_button.place(x=380, y=18)

''' Middle Menu '''
chat_log = Text(s_root, width = 65, height = 29, state = 'disabled', spacing2 = 2) ; chat_log.place(x=20, y=60)

''' Bottom Menu '''
close_button = Button(s_root,text='Server Close',command=server_close); close_button.place(x=200, y = 460)
s_root.mainloop()

클라이언트 소스코드

import socket
from _thread import *
import threading
from tkinter import *
from time import sleep

def send(socket):
    global go_send
    while True:
        if go_send:
            message = (message_input.get(1.0,"end")).rstrip()
            socket.send(message.encode())
            message_input.delete(1.0, "end")
            go_send = False
        else:
            if go_out:
                socket.close()
                exit()
            sleep(0.1)

def receive(socket):
    first = True
    while True:
        try:
            data = socket.recv(1024)
            chat_log['state'] = 'normal'
            if first: # 이걸 처음 체크 이후 의미없이 매번 체크하므로 이렇게 하는 건 효율적이지 않음.
                chat_log.insert("end",str(data.decode( )))
                first = False
            else:
                chat_log.insert("end",'\n' + str(data.decode()))
                chat_log.see('end')
            chat_log['state'] = 'disabled'
        except ConnectionAbortedError as e:
            chat_log['state'] = 'normal'
            chat_log.insert("end", '\n[System] 접속을 종료합니다.\n')
            chat_log['state'] = 'disabled'
            exit()

def login():
    # 서버의 ip주소 및 포트
    HOST = ip_entry.get(); PORT = int(port_entry.get())
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect((HOST, PORT))

    threading.Thread(target=send, args= (client_socket,)).start()
    threading.Thread(target=receive, args= (client_socket,)).start()
    exit()

def try_login():
    global go_out
    start_new_thread(login,())
    login_button['state'] = 'disabled'
    logout_button['state'] = 'active'
    ip_entry['state'] = 'readonly'
    port_entry['state'] = 'readonly'
    go_out = False

def try_logout():
    global go_out
    login_button['state'] = 'active'
    logout_button['state'] = 'disabled'
    ip_entry['state'] = 'normal'
    port_entry['state'] = 'normal'
    go_out = True

def set_go_send(event):
    global go_send
    go_send = True

go_out, go_send = False, False
c_root = Tk()
c_root.geometry('500x500')
c_root.title('Client')
c_root.resizable(False, False)

''' Top Menu '''
Label(c_root, text = 'Server IP : ').place(x=20, y=20)
Label(c_root, text = 'Port : ').place(x=250, y=20)
ip_entry = Entry(c_root, width=14); ip_entry.place(x=83, y=21)
ip_entry.insert(0,'127.0.0.1')
port_entry = Entry(c_root, width=5); port_entry.place(x = 290, y=21)
port_entry.insert(0,'9999')
login_button = Button(c_root,text='Log In', command=try_login); login_button.place(x=350, y=18)
logout_button = Button(c_root,text='Log Out',state = 'disabled', command = try_logout); logout_button.place(x=420, y=18)

''' Middle Menu '''
chat_frame = Frame(c_root)
scrollbar = Scrollbar(chat_frame) ; scrollbar.pack(side='right',fill='y')
chat_log = Text(chat_frame, width = 62, height = 24, state = 'disabled', yscrollcommand = scrollbar.set) ; chat_log.pack(side='left')#place(x=20, y=60)
scrollbar['command'] = chat_log.yview
chat_frame.place(x=20, y=60)
message_input = Text(c_root, width = 55, height = 4) ; message_input.place(x=20,y = 390)
send_button = Button(c_root, text = 'Send', command = lambda: set_go_send(None)); send_button.place(x=430, y=405)
message_input.bind("<Return>",set_go_send)

''' Bottom Menu '''
close_button = Button(c_root,text='Close',command=exit); close_button.place(x=200, y = 460)

c_root.mainloop()
반응형
저작자표시 비영리 변경금지 (새창열림)

'개인 프로젝트 > 토이 프로젝트' 카테고리의 다른 글

[개인프로젝트] 수원시 공고알림 크롤링 및 메일링 프로그램 제작  (0) 2024.02.10
[개인프로젝트] BOJ 크롤링을 통한 동아리 출석체크 보조 프로그램 제작  (0) 2021.01.10
'개인 프로젝트/토이 프로젝트' 카테고리의 다른 글
  • [개인프로젝트] 수원시 공고알림 크롤링 및 메일링 프로그램 제작
  • [개인프로젝트] BOJ 크롤링을 통한 동아리 출석체크 보조 프로그램 제작
에버듀
에버듀
개발은 좋은데 뭘로 개발할까
  • 에버듀
    Blog. 에버듀
    에버듀
  • 전체
    오늘
    어제
    • 분류 전체보기 (615)
      • 개인 프로젝트 (43)
        • 토이 프로젝트 (3)
        • [2020] 카카오톡 봇 (9)
        • [2021] 코드악보 공유APP (22)
        • [2022] 유튜브 뮤직 클론코딩 (9)
        • [2025] 한글 SQL 데이터베이스 (0)
      • 팀 프로젝트 (22)
        • [2020] 인공지능 숫자야구 (4)
        • [2022] OSAM 온라인 해커톤 (10)
        • [2024] GDSC 프로젝트 트랙 (6)
        • [2025] 큰소리 웹 페이지 (2)
      • CS (335)
        • 자료구조 (19)
        • 어셈블리 (41)
        • 멀티미디어응용수학 (7)
        • 컴퓨터 구조 (29)
        • 알고리즘 분석 (4)
        • 컴퓨터 네트워크 (38)
        • 프로그래밍언어론 (15)
        • HCI 윈도우즈프로그래밍 (26)
        • 기초데이터베이스 (29)
        • 운영체제 (23)
        • 오토마타 (24)
        • 문제해결기법 (11)
        • 블록체인 (22)
        • 소프트웨어공학 (21)
        • 기계학습심화 (12)
        • 컴퓨터그래픽스와 메타버스 (8)
        • 분산시스템특론 (6)
      • 자기계발 (45)
        • 생각 정리 (23)
        • 대외활동 (11)
        • 동아리 (7)
        • 자격증 (3)
        • 머니 스터디 (1)
      • 알고리즘 (PS) (107)
        • BOJ (101)
        • Programmers (5)
        • 알고리즘 이모저모 (1)
      • WEB(BE) (8)
        • express.js (1)
        • Spring & Spring Boot (7)
      • WEB(FE) (2)
        • html, css, js (1)
        • React.js (1)
      • Tool & Language (6)
        • Edit Plus (1)
        • Git (1)
        • Python3 (2)
        • Java (2)
      • Infra (12)
        • AWS (1)
        • Oracle Cloud (8)
        • Firebase (2)
        • Network (1)
      • Android (18)
        • Java (6)
        • Flutter (12)
      • Window (2)
        • Visual Studio 없이 WPF (1)
        • MFC (1)
      • 독서 (14)
        • Inside Javascript (7)
        • Database Internals (6)
        • 한 글 후기 (1)
  • 링크

    • github
    • website
  • 인기 글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
에버듀
[개인프로젝트] tkinter로 GUI 입힌 tcp/ip 소켓 통신 프로그램 만들기
상단으로

티스토리툴바