물먹는산세베리아

python 소켓프로그래밍으로 1:1 채팅 구현 본문

Language/Python

python 소켓프로그래밍으로 1:1 채팅 구현

suntall 2020. 9. 7. 04:16

1. server.py

1) 모듈 import

- 소켓 생성

- 스레드 생성/ form threading impot* ->threading.Thread() 대신 Thread() 사용 가능

- sleep() 함수 사용

 

2) 소켓 송수신

서로 주고 받는 대화를 하기 위해서 계속 입력받을수 있도록, 계속 전달 받을 수 있도록 while문으로 반복문을 작성하였다. 일단 메세지를 주고 받기 위해 인자를 sock으로 받아왔다. 위 코드에서 sock.send()는 보내는 메소드, sock.recv()는 받는 메소드이다. 메세지를 보낼 때 입력한 문자열은 encode()을 사용하여 byte로 변환하는데, 파이썬의 문자열은 객체이기 때문에 바로 전달될 수 없다. 따라서 인코딩을 해주어야 한다. 상대방의 메세지를 받을 때는 수신할 바이트의 크기를 정해주는데. 위 코드에서는 1024라고 정하였다. 만약 입력 값이 1024바이트를 넘기면 다음에 메세지를 받을 때 이어서 전달된다. 메세지를 받을 때 역시 디코딩해주어야 한다. 바이트 값이 넘어오기 때문에 다시 이를 문자열로 변환해 주어야 하기 때문이다.

 

위는 소켓을 만드는 과정이다. 서버를 구축하기 위해 socket 객체를 만들었다. 이때 두 가지를 인자로 받는데 먼저, AF_INET는 IPv4를 의미하므로 IP 주소를 쓰는 자리이다. (*cmd 창에서 ifconfig로 IP주소 확인 가능) 그리고 SOCK_STREAM이 있는 자리는 소켓 타입을 받는다.

 

* 소켓 타입은 보편적으로 stream 소켓과 datagream 소켓을 쓴다. stream 소켓은 양방향 통신을 제공하며 보낸 내용의 도착 여부를 확인 할 수 있다. TCP를 사용하여 웹 서버에 주로 쓰인다. 반면 데이터그램 소켓은 단방향성이고, UDP(데이터그램 프로토콜) 표준 프로토콜을 사용하여 주로 게임, 미디어 스트리밍에 쓰인다.

따라서 여기서는 양방향 소켓 타입이 필요하기 때문에 sock_stream을 썼다.

 

다음으로 bind(ip, port)으로 소켓의 번호와 AF(어드레스 패밀리)를 연결해주고 1:1 채팅 프로그램이므로 serverSock.listen() 인자 안에 1을 입력하여 1명만 들어 올 수 있도록 설정하였다.

 

server.py 실행

여기서 서버를 열면 클라이언트에서 접속 하기 전까지 위와 같이 접속 대기 중이라고 출력된다.

 

클라이언트가 접속하여 연결하기 위해서 accept()를 써 주었다. 클라이언트가 접속하면 serverSock.accept()로 새로운 소켓과 클라이언트의 주소 값을 리턴하여 전달받는다. 여기서 얻은 새로운 소켓인 connectionSock은 서로 데이터를 주고 받는 데 사용되는 소켓이다.

server.py 실행 후 client.py 실행

클라이언트가 접속하면 뒤처럼  어디에서 접속되었는지 출력한다.

 

3) Thread 생성(순서 상관 없는 주고 받기)

서버와 클라이언트가 메시지를 보낼 때 서로 한 번씩 주고받는 게 아니라 순서 상관 없이 보낼 수 있도록 하기 위해 Thread를 사용하였다. threading.Tread로 스레드를 생성하여 동시에 일을 처리할 수 있도록 하였다. target에는 스레드를 실행할 함수를, args에는 함수에 전달할 인자를 입력한다. 튜플로 인식시키기 위해 connectionSock에 ,도 같이 입력하였다.

이렇게 스레드가 생성되고 start()가 일을 시작하면 한번은 채팅을 할 수 있지만 지속적으로 메세지를 주고 받기 위해 계속 일을 하도록 만들어 주어야 한다. 그래서 send()함수와 receive()함수에 while True를 넣어 일을 계속하도록 설정하였다.

하지만 프로세스가 종료되면 스레드도 종료되므로 프로그램이 강제로 종료되지 않는 이상 계속 할 수 있도록 마지막에 while True: pass를 추가해준다. time.sleep(1)은 중간에 1초정도 멈추어 에너지를 낭비하지 않도록 하는 역할을 한다.

 

2. client.py

1) 모듈 import

- 소켓 생성

- 스레드 생성/ form threading impot* ->threading.Thread() 대신 Thread() 사용 가능

- sleep() 함수 사용

 

2) 소켓 송수신

서버 코드와 같다. 다만, 클라이언트가 Q라고 입력했을 경우 클라이언트의 소켓을 강제로 닫아버리고 대화 종료를 출력하도록 작성하였다.

서버 소켓을 형성할 때처럼 작성하되 서버 접속을 위해 connect를 사용하였다. IP주소에 n번 포트를 연결하라는 의미이다. 이때 서버 측에서는 accept 함수를 통해 연결이 되고, 대화를 시작할 수 있다.

 

3) Thread 생성

서버 코드의 connectionSock 자리에 clientSock이 들어간다. 이로써 서로 연결이 되었고 계속해서 순서 상관 없이 주고 받을 수 있는 상태가 되었다.

 

3. 전체 코드 및 실행

server.py
client.py