방학때 몇일 날잡아서 멀티쓰레드 채팅 서버를 만들어보려고 했는데 의외로 여태까지 한 수련이
헛되진 않았는지 하루동안 열심히 투자하니까 틀은 완성됬다. 이번 코딩을 하면서
오히려 서버 클라이언트 사이의 작동보다는 유니코드 인코딩 관련 조사를 가장 많이 한것 같다.
근데 소스코드를 다시 살펴보면 정말 초심자가 짠 어색하고 더러운 코드다....
방법이 있긴 한거같은데 몰라서 야매로,더럽게 구현한것도 많다.
실행결과.
첫 실행 결과. 왼쪽 서버, 오른쪽 클라이언트이다. 서버는 gui화 안했고 클라이언트만 gui.
접속하면 접속한 유저의 아이피주소와 내가 유저몇인지 뜸..
왼쪽이 서버이고 클라이언트를 하나 더 실행시켰을때 화면. 원래 있던 유저 1에도 유저 2가 접속했다고
뜨는것을 확인할수 있다.
메시지를 쓰고 보내기버튼을 누르면 서버, 내 자신, 다른 클라이언트의 화면에까지 채팅내용이 뜬다.
유저 2도 마찬가지...
유저 2가 나가기버튼을 눌러 나간경우 나갔다고 뜬다.
개선점 : 예외처리를 더 정교하게 처리, 마우스클릭말고 엔터 눌렀을때도 채팅메시지 보내기, 서버측도 gui로 구현, 클라이언트의 창을 더 효과적으로 나누기,클라이언트 입장 시 호칭 정하기 등등등
서버.
# -*- encoding: cp949 -*- import socket,threading,Tkinter sem = threading._Semaphore() count = 0 #클라이언트 순서번호 매기기 th = []; conns = [] #쓰레드 집어넣을 리스트, def to_client(conn,addr,count): cnt = count global conns for i in range(len(conns)): conns[i].sendall('%s에서, 유저 %d님이 접속하였습니다.' %(addr[0],cnt)) print '%s에서, 유저 %d님이 접속하였습니다.' %(addr[0],cnt) conn.sendall('서버에 접속하셨습니다.\n당신은 유저 %d입니다' %cnt) try: while 1: read = conn.recv(1000) if read=='-1': conn.sendall('-1') exit(0) read = '유저 %d : %s' %(cnt,read) print read for i in range(len(conns)): conns[i].sendall(read) except: print '유저 %d 님이 나가셨습니다.' %cnt conns.remove(conn) for i in range(len(conns)): conns[i].sendall('유저 %d 님이 나가셨습니다.' %cnt) exit(0) s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.bind(('127.0.0.1',50000)) s.listen(1) while 1: conn,addr = s.accept() conns.append(conn) sem.acquire(); count += 1; sem.release() client = threading.Thread(target=to_client,args=(conn,addr,count)) client.start() th.append(client); for t in th: t.join()
클라이언트.
# -*- encoding: cp949 -*- import socket,threading,Tkinter th = [] def listen(s): global text while 1: read = s.recv(1000) if read=='-1': exit(0) text.insert('insert',unicode(read,'cp949')) text.insert('insert','\n') def button1Click(event): global s global E if E.get()=='-1': s.sendall('-1') s.sendall( E.get().encode('cp949') ) def button2Click(event): global s s.sendall('-1') root.destroy() s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(('127.0.0.1',50000)) try: root = Tkinter.Tk() f = Tkinter.Frame(root) f.pack() L = Tkinter.Label(f, text=unicode("메시지 : ",'cp949')) L.pack( side = 'left') E = Tkinter.Entry(f, bd =5) E.pack(side = 'left') text=Tkinter.Text(root) text.pack() text.insert('insert',unicode(s.recv(1000),'cp949')) text.insert('insert','\n\n') button2=Tkinter.Button(f,text=unicode('나가기','cp949'),background='red') button2.pack(side='right') button2.bind('<Button-1>',button2Click) l = threading.Thread(target=listen,args=(s,)) th.append(l) l.start() button1=Tkinter.Button(f,text=unicode('보내기','cp949'),background='white') button1.pack(side='right') button1.bind('<Button-1>',button1Click) root.mainloop() except: pass exit(0) for t in th: t.join()
'Python > 2.7 for fun.' 카테고리의 다른 글
네이버 블로그에서 최근에 올라온 음악들 다운받기 1 블로그 구조 분석 (0) | 2015.03.15 |
---|---|
(편의) pyqt를 이용한 gui 만화책 정리 스크립트. (0) | 2015.03.01 |
(편의) 만화책 정리 스크립트. (1) | 2015.02.27 |
py2exe, (편의) 티스토리에 맞는 파이썬 소스코드 변환기 (0) | 2015.02.23 |
사칙연산 계산 서버, 클라이언트 (0) | 2014.10.03 |