18.5강. Part 1 ~ 4 코드 점검

0. 학습 목표
→ 이번 글에서 무엇을 점검하고, 무엇을 확인할지 먼저 정리합니다.
0.1 이번 글에서 다룰 내용
이번 글은 점검 중심 강의입니다.
새 기능을 추가하기보다 지금까지 만든 코드를 다시 실행하면서 전체 흐름이 안정적으로 동작하는지 확인합니다. 지금까지 만든 기능은 다음과 같습니다.
P1 네트워크 입문: IP, 포트, TCP, 소켓 개념
P2 1:1 소켓 통신: 서버·클라이언트 연결, 메시지 송수신
P3 다중 접속과 브로드캐스팅: 스레드, 접속자 목록, 전체 채팅
P4 메시지 프로토콜: JSON, 패킷 경계, 메시지 타입 분기
기능 하나씩은 잘 동작해도 전체로 연결했을 때 오류가 생길 수 있습니다. 이번 강의에서는 실행 순서, 파일 구성, 메시지 형식, 자주 발생하는 오류를 하나씩 점검합니다.

| 구분 | 내용 |
| 확인할 것 | P1~P4 기능들이 하나의 채팅 서버 구조로 연결되어 안정적으로 동작하는지 |
| 점검 방법 | 서버 실행 → 클라이언트 다중 접속 → 기능별 테스트 → 오류 상황 대응 |
| 완료 기준 | 섹션 6의 체크리스트 12개 항목을 모두 통과하면 완료 |
0.2 이번 강의에서 점검할 구조
이번 체크포인트는 17~18강 기준의 최종 구조를 점검합니다. 세 파일이 올바른 위치에 있어야 합니다.
chat_server/
├── protocol.py ← 점검 (JSON 송수신·버퍼 처리)
└── server.py ← 점검 (스레드·접속자 목록·브로드캐스팅·type 분기)
chat_client/
└── client.py ← 점검 (수신 스레드·type별 출력)
| 파일 | 역할 |
protocol.py |
JSON 메시지를 보내고, 받은 데이터를 버퍼에 모아 메시지 단위로 분리한다 |
server.py |
여러 클라이언트를 스레드로 처리하고, 전체 채팅과 시스템·오류 메시지를 관리한다 |
client.py |
사용자가 입력한 메시지를 보내고, 수신 스레드로 서버 메시지를 계속 받는다 |
0.3 📦 Part 1 ~ 2 구현
part3_4_final.zip
├── README.md
├── chat_server/
│ ├── protocol.py ← 공통 송수신 규칙
│ └── server.py ← 다중 접속 채팅 서버 (17강 완성본)
└── chat_client/
├── protocol.py ← 서버와 동일 (복사본)
└── client.py ← 수신 스레드 포함 클라이언트 (17강 완성본)
1. 현재까지 만든 기능 확인하기
→ P1~P4 흐름과 이번 체크포인트에서 확인할 최종 기준을 정리합니다.
1.1 P1~P4 흐름 정리
| 파트 | 주요 내용 | 현재 코드와의 연결 |
| P1 네트워크 입문 | IP, 포트, TCP, 소켓 개념 | HOST, PORT, socket 사용의 의미 |
| P2 1:1 소켓 통신 | 서버·클라이언트 연결, 메시지 송수신 | server.py, client.py 기본 구조 |
| P3 다중 접속과 브로드캐스팅 | 스레드, 접속자 목록, 전체 채팅 | threading, clients, broadcast() |
| P4 메시지 프로토콜 | JSON, 패킷 경계, 메시지 타입 | protocol.py, type 기반 분기 |
1.2 이번 체크포인트 완료 기준
아래 질문에 모두 "예"라고 답할 수 있으면 P1~P4 기능이 하나의 구조로 연결된 것입니다.
1. 서버가 오류 없이 실행되는가?
2. 클라이언트 2개 이상이 동시에 접속되는가?
3. 클라이언트 접속 시 접속자 수가 증가하는가?
4. 클라이언트 종료 시 접속자 수가 감소하는가?
5. 한 클라이언트의 메시지가 다른 클라이언트에게 전달되는가?
6. 입장과 퇴장이 시스템 메시지로 표시되는가?
7. 빈 메시지가 오류 메시지로 처리되는가?
8. JSON 메시지가 구분자 기준으로 안정적으로 분리되는가?
2. 프로젝트 구조 점검하기
→ 파일 위치와 protocol.py 핵심 코드를 확인합니다.
2.1 파일 위치 확인하기
server.py와 client.py는 protocol.py를 import합니다.
from protocol import receive_messages, send_message
protocol.py가 같은 폴더에 없으면 이 줄에서 ModuleNotFoundError가 발생합니다. 서버 폴더 안에 두 파일이 모두 있는지 확인합니다.
ls chat_server/
protocol.py server.py
ModuleNotFoundError: No module named 'protocol'이 나오는 가장 흔한 원인은 터미널의 현재 위치가 파일이 있는 폴더가 아닌 경우입니다. python chat_server/server.py처럼 경로를 포함해 실행하면 Python이 chat_server/ 폴더가 아니라 터미널의 현재 폴더를 기준으로 import를 찾습니다. 가장 간단한 방법은 세 파일을 같은 폴더에 두고 그 폴더에서 실행하는 것입니다.
2.2 protocol.py 핵심 코드 점검하기
protocol.py에서 특히 다음 세 가지를 확인합니다.
| 점검 항목 | 확인 코드 | 이유 |
| 구분자 정의 | DELIMITER = "\n" |
메시지 끝을 구분하기 위해 필요하다 |
| 전체 전송 | sock.sendall(data.encode(ENCODING)) |
JSON 문자열과 구분자를 끝까지 보내기 위해 사용한다 |
| 버퍼 반환 | return buffer, messages, True |
덜 받은 메시지를 다음 수신 때 이어서 처리하기 위해 반환한다 |
✔ 확인 기준: chat_server/ 폴더에 protocol.py와 server.py가 함께 있고, protocol.py 안에 세 항목이 모두 있으면 완료.
3. 실행 순서 점검하기
→ 서버를 먼저 실행하고, 클라이언트 여러 개를 접속합니다.
3.1 서버 먼저 실행하기
서버는 항상 클라이언트보다 먼저 실행해야 합니다.
python chat_server/server.py
시스템/오류 메시지 처리 서버를 시작합니다.
클라이언트 접속 대기 중...
서버가 이 상태에서 멈춘 것처럼 보이는 것이 정상입니다. accept()에서 클라이언트 접속을 기다리는 상태입니다.
3.2 클라이언트 여러 개 실행하기
터미널 2와 3에서 각각 클라이언트를 실행합니다.
python chat_client/client.py
서버에 연결되었습니다.
전체 채팅을 시작합니다. 종료하려면 exit을 입력하세요.
두 번째 클라이언트가 접속하면 첫 번째 클라이언트 화면에 시스템 메시지가 표시되어야 합니다.
[시스템] ('127.0.0.1', 52345) 님이 입장했습니다.
✔ 확인 기준: 두 클라이언트 모두 입력 대기 상태가 되고, 서버에 "현재 접속자 수: 2" 출력, 첫 번째 클라이언트에 입장 시스템 메시지가 표시되면 완료. 서버를 먼저 실행했는지, 포트 5000이 이미 사용 중인지 확인하세요.
4. 기능별 테스트하기
→ 접속자 목록·브로드캐스팅·시스템 메시지·오류 메시지·종료 처리를 순서대로 확인합니다.
4.1 접속자 목록 테스트
| 테스트 | 입력 또는 동작 | 예상 결과 |
| 첫 번째 클라이언트 접속 | python chat_client/client.py |
서버: 현재 접속자 수: 1 |
| 두 번째 클라이언트 접속 | 새 터미널에서 python chat_client/client.py |
서버: 현재 접속자 수: 2 |
| 클라이언트 종료 | exit 입력 |
서버: 현재 접속자 수: 1 |
4.2 전체 채팅 브로드캐스팅 테스트
| 테스트 | 입력 또는 동작 | 예상 결과 |
| A → B 메시지 전달 | 터미널 2에서 "안녕하세요 A입니다" 입력 | 터미널 3에 ('127.0.0.1', 52344): 안녕하세요 A입니다 표시 |
| B → A 메시지 전달 | 터미널 3에서 "안녕하세요 B입니다" 입력 | 터미널 2에 ('127.0.0.1', 52345): 안녕하세요 B입니다 표시 |
| 자기 메시지 미수신 | 어느 클라이언트에서든 메시지 입력 | 보낸 클라이언트 화면에는 자기 메시지가 다시 표시되지 않음 |
4.3 시스템 메시지 테스트
| 테스트 | 상황 | 예상 결과 |
| 입장 알림 | 새 클라이언트 접속 | 기존 클라이언트 화면에 [시스템] ... 님이 입장했습니다. 표시 |
| 퇴장 알림 | 클라이언트 exit 입력 |
나머지 클라이언트 화면에 [시스템] ... 님이 퇴장했습니다. 표시 |
4.4 오류 메시지 및 종료 처리 테스트
| 테스트 | 입력 또는 동작 | 예상 결과 |
| 빈 메시지 전송 | Enter만 입력 | 해당 클라이언트에만 [오류] 빈 메시지는 보낼 수 없습니다. 표시. 다른 클라이언트에게는 전달 안 됨 |
| exit 후 서버 유지 | exit 입력 |
서버가 계속 실행되고 나머지 클라이언트가 채팅 가능 |
✔ 확인 기준: 위 테스트 항목들이 모두 예상 결과와 일치하면 완료. 실패 항목이 있으면 섹션 5의 오류 해결 방법을 참고하세요.
5. 자주 발생하는 오류 해결하기
→ 이번 체크포인트에서 자주 만나는 오류와 해결 방법을 정리합니다.
| 오류 상황 | 원인 및 해결 방법 |
ModuleNotFoundError: No module named 'protocol' |
protocol.py가 server.py·client.py와 다른 폴더에 있거나 실행 위치가 다름. 같은 폴더에서 실행하거나 파일 위치를 확인한다 |
ConnectionRefusedError |
서버가 실행되지 않은 상태에서 클라이언트를 실행했음. python chat_server/server.py를 먼저 실행한다 |
Address already in use |
이전 서버가 포트 5000을 계속 사용 중. 기존 서버 터미널을 종료하고 다시 실행한다 |
json.decoder.JSONDecodeError |
완성되지 않은 JSON을 해석했거나 구분자가 빠졌음. send_message()로만 보내고 receive_messages()에서 분리된 메시지만 해석하는지 확인한다 |
| 메시지가 다른 클라이언트에 보이지 않음 | broadcast()가 호출되지 않았거나 clients 목록이 비어 있음. 접속 시 clients.append()와 채팅 시 broadcast() 호출을 확인한다 |
| 오류 메시지가 전체 클라이언트에게 보임 | 오류를 broadcast()로 보냈음. send_error()로 해당 클라이언트에게만 보낸다 |
UnicodeDecodeError |
인코딩 방식이 다름. protocol.py의 ENCODING = "utf-8"을 확인한다 |
| 입력 줄과 수신 메시지가 섞여 보임 | 터미널 입력과 수신 스레드 출력이 동시에 발생하는 것. 터미널 버전에서는 정상이다. GUI 단계에서 개선된다 |
Address already in use가 발생할 때 추가로 확인할 사항입니다.
이전에 실행한 서버 터미널이 아직 켜져 있는가?
같은 폴더에서 서버를 여러 번 실행하지 않았는가?
server.py와 client.py의 PORT = 5000이 동일한가?
json.decoder.JSONDecodeError가 발생할 때 추가로 확인할 사항입니다.
메시지를 보낼 때 send_message()를 사용했는가?
send_message() 안에서 메시지 끝에 \n 구분자가 붙는가?
서버·클라이언트 중 한쪽이 예전 방식인 send()를 여전히 사용하고 있지 않은가?
6. 체크리스트로 마무리하기
→ 아래 항목을 하나씩 확인하며 P1~P4 기능이 정상적으로 연결되었는지 최종 점검합니다.
| 점검 항목 | 완료 |
protocol.py, server.py, client.py가 올바른 위치에 있다 |
☐ |
서버가 python chat_server/server.py로 실행된다 |
☐ |
클라이언트가 python chat_client/client.py로 접속된다 |
☐ |
| 클라이언트 2개 이상이 동시에 접속된다 | ☐ |
| 접속자 수가 접속 시 증가한다 | ☐ |
| 접속자 수가 종료 시 감소한다 | ☐ |
| 일반 채팅이 다른 클라이언트에게 전달된다 | ☐ |
입장 메시지가 [시스템]으로 표시된다 |
☐ |
퇴장 메시지가 [시스템]으로 표시된다 |
☐ |
빈 메시지가 [오류]로 처리된다 |
☐ |
exit 입력 시 정상 종료된다 |
☐ |
| 다른 클라이언트가 종료해도 서버는 계속 실행된다 | ☐ |
✔ 확인 기준: 체크리스트 12개 항목 모두 통과하면 이번 체크포인트 완료. 통과하지 못한 항목이 있으면 해당 기능을 담당하는 강의(P2~P4)로 돌아가 코드를 다시 확인하세요.
7. 다음 파트로 이어지는 부분
→ P1~P4 완성 기능을 정리하고 19강에서 준비할 내용을 예고합니다.
이번 체크포인트까지 터미널 기반 다중 채팅 서버의 핵심 기능을 완성했습니다. 현재 코드에 들어 있는 기능을 정리합니다.
다중 클라이언트 접속 (스레드 기반)
접속자 목록 관리 (clients 리스트)
전체 채팅 브로드캐스팅 (broadcast())
JSON 메시지 프로토콜 (protocol.py)
패킷 경계 처리 (buffer + \n 구분자)
시스템 메시지와 오류 메시지 (type 분기)
이제 GUI로 옮기기 위한 준비가 필요합니다. 바로 GUI를 만들기 전에 19강에서는 코드를 클래스 구조로 정리합니다. 현재 코드는 학습하기에 좋지만 기능이 늘어나면 전역 변수와 함수가 많아집니다. GUI와 연결하려면 서버와 클라이언트의 역할을 더 명확한 구조로 분리해야 합니다.
현재 (함수 중심):
clients = [] ← 전역 변수
def broadcast(): ← 전역 함수
def handle_client(): ← 전역 함수
19강 이후 (클래스 구조):
class ChatServer:
def __init__(self): self.clients = []
def broadcast(self): ...
def handle_client(self): ...
→ 다음 강의 (19강): 현재 함수 중심 코드를 역할별 클래스로 리팩토링합니다. ChatServer와 ChatClient 클래스를 만들어 전역 변수를 없애고, GUI와 연결하기 쉬운 구조를 준비합니다.