minari0v0
소개프로젝트스토리

© 2026 minari0v0. All rights reserved.

모든 프로젝트GitHub 저장소

Java 소켓 기반 온라인 오목 게임

Java 소켓 통신과 Swing을 활용하여 구현한 2인용 오목 게임

JavaSwingSocketMySQLTCP/IPMulti-threadingOOP
Java 소켓 기반 온라인 오목 게임
개발 기간
2024년 10월~2024년 12월
프로젝트 유형
개인 프로젝트
기술 스택 (Tech Stack)
Frontend
Swing
Backend
Java
Database
MySQL

프로젝트 개요

순수 Java 기술 스택만으로 온라인 멀티플레이어 오목 게임을 구현한 데스크톱 애플리케이션입니다. Java의 소켓(Socket) 통신을 이용한 멀티 스레딩 서버를 직접 구축하고, Java Swing의 그래픽 기능을 활용한 GUI 클라이언트를 개발했습니다.

단순한 게임 구현을 넘어, 실시간 채팅, 랭킹 시스템, 외부 API 연동, 관리자용 대시보드 등 실제 서비스에 필요한 다양한 기능을 포함하여 백엔드부터 프론트엔드, 데이터베이스까지 아우르는 종합적인 개발 경험을 목표로 했습니다.

프로젝트 구조

.
├── src
│   ├── main
│   │   ├── java
│   │   │   ├── client      # 클라이언트 측 로직 및 UI
│   │   │   ├── server      # 서버 측 로직 및 통신
│   │   │   ├── GUI         # 공용 GUI 컴포넌트
│   │   │   └── img         # UI에 사용된 이미지 및 리소스
│   │   └── webapp
├── build                   # 컴파일된 클래스 파일
├── ...
└── README.md

기술 스택 및 아키텍처

분류기술
FrontendJava Swing, Custom UI Components
BackendJava 8+, Socket (TCP/IP), JavaMail API
DatabaseMySQL 8.0, JDBC
APIs / LibsWeather/Address API, Thumbnailator, Serialization
ToolsEclipse IDE, MySQL Workbench

DB 설계

주요 테이블

-- 사용자 정보 (userinfo)
users (id, nickname, password, profile_img_path, win, lose)
 
-- 채팅 로그 (messages)
messages (id, from_user, to_user, message, timestamp, room_name)
 
-- 삭제된 사용자 (userinfo_bin)
userinfo_bin (id, nickname, password, profile_img_path, win, lose)
 
-- 삭제된 채팅 (messages_bin)
messages_bin (id, from_user, to_user, message, timestamp, room_name)

UI/UX 특징

커스텀 컴포넌트

  • 말풍선 채팅: 1대1 채팅에서 말풍선 형태의 메시지 표시
  • 이모티콘 시스템: 다양한 이모티콘을 통한 감정 표현 및 활용
  • 팔레트 기능: 채팅창 배경 및 테마 색상 커스터마이징
  • 비밀번호 보안도 프로그레스 바: 회원가입 시 비밀번호 보안 수준 시각적 표시
  • 커스텀 오목판: paintComponent를 오버라이드하여 오목판의 격자, 화점, 사용자 프로필 오목돌, 승리 표시 등 게임 UI 시각화
  • 디자인 일관성: 커스텀 스크롤바(CustomScrollBarUI) 및 폰트(FontLoader) 적용을 통한 통일된 디자인 제공

사용자 편의성 기능

  • 풍부한 채팅 옵션: 로비/게임방/1:1 귓속말 채팅 및 1:1 채팅 내 키워드 검색 기능
  • 직관적 게임방 관리: 난수 코드/비밀번호 설정 방 생성 및 관전 기능 제공
  • 부가 정보 제공: 실시간 날씨 위젯(Public Data Portal API 연동) 및 승률 기반 랭킹 시스템
  • 사용자 프로필 편집: 프로필 이미지 업로드 시 원하는 영역 자르기 및 리사이징(Thumbnailator 활용)

주요 기능

1. 실시간 멀티플레이어 게임

TCP/IP 소켓 통신 기반의 서버

  • 15x15 오목판 구현
  • 4방향 승리 조건 검사 (수평, 수직, 대각선)
  • 관전 모드 지원 (최대 2인, 총 인원 4명)

게임화면 오목 게임 화면 - 조준점, 플레이어 목록, 채팅창, 게임 버튼 등의 인터페이스

2. 동적 게임방 시스템

  • 난수 코드를 이용한 게임방 생성
  • 비밀번호 설정으로 비공개 방 운영
  • 관전자 허용 여부 설정 기능

방생성

3. 풍부한 채팅 경험

  • 말풍선 형태의 커스텀 UI (ChatBubblePanel)
  • 로비/게임방/1:1 개인 채팅 지원
  • 이모티콘 및 채팅창 테마 변경 기능
  • 1:1 채팅 내 특정 키워드 검색 기능

채팅창

4. 커뮤니티 및 편의 기능

  • DB 연동 승률 기반 랭킹 시스템 (CustomPanel 활용 메달 배경 렌더링)
  • 공공 데이터 포털 연동 날씨 위젯 (로그인/로비 화면 표시)
  • 프로필 이미지 편집/저장 (thumbnailator, CropImageWindow 활용)

랭킹

5. 관리자 대시보드 (ChatServerGUI)

  • 서버 로그 실시간 모니터링
  • 전체 회원 정보 조회/수정/삭제/복원 (Soft-delete)
  • 접속 중인 유저 강제 추방 기능
  • 유저 채팅 기록 조회 및 메시지 삭제/복원 (백업 테이블 연동)

대시보드

핵심 기술

1. 멀티 스레딩 서버 구현 (ChatServer.java)

클라이언트가 접속할 때마다 새로운 ClientHandler 스레드를 생성하여, 여러 클라이언트의 요청을 동시에 처리하는 멀티 스레딩 서버의 핵심 로직

// in ChatServer.java
public void startServer() {
    isRunning = true;
    try {
        serverSocket = new ServerSocket(12345);
        System.out.println("<관리자> 채팅 서버가 시작되었어요..");
 
        while (isRunning) {
            try {
                Socket clientSocket = serverSocket.accept(); // 클라이언트 접속 대기
                System.out.println("<관리자> 새로운 클라이언트가 연결됐어요");
                
                // 클라이언트마다 별도의 스레드 생성 및 시작
                ClientHandler clientHandler = new ClientHandler(this, clientSocket);
                clients.add(clientHandler);
                new Thread(clientHandler).start();
 
            } catch (SocketException e) {
                if (!isRunning) {
                    System.out.println("<관리자> 서버가 종료되었어요.");
                    break;
                }
                throw e;
            }
        }
    } catch (IOException e) {
        // ...
    }
}

2. 오목 승리 판정 로직 (Room.java)

특정 위치에 돌이 놓였을 때, 가로, 세로, 양 대각선 방향으로 같은 색의 돌이 5개 이상 연속되는지를 확인하여 승패를 판정하는 알고리즘

// in server/Room.java
private boolean checkWin(int x, int y, int stone) {
    return checkDirection(x, y, 1, 0, stone) || // 가로
           checkDirection(x, y, 0, 1, stone) || // 세로
           checkDirection(x, y, 1, 1, stone) || // 대각선 ↘
           checkDirection(x, y, 1, -1, stone);  // 대각선 ↗
}
 
private boolean checkDirection(int x, int y, int dx, int dy, int stone) {
    int count = 1;
 
    // 한 방향 체크
    for (int i = 1; i < 5; i++) {
        int nx = x + i * dx;
        int ny = y + i * dy;
        if (nx < 0 || nx >= gridSize || ny < 0 || ny >= gridSize || board[nx][ny] != stone) break;
        count++;
    }
 
    // 반대 방향 체크
    for (int i = 1; i < 5; i++) {
        int nx = x - i * dx;
        int ny = y - i * dy;
        if (nx < 0 || nx >= gridSize || ny < 0 || ny >= gridSize || board[nx][ny] != stone) break;
        count++;
    }
 
    return count >= 5; // 5개 이상 연결되면 승리
}

3.주소 검색 API 연동 (MapApi.java)

// 우체국 도로명주소 API를 호출하여 주소를 검색하는 기능
// HTTP 요청으로 XML 응답을 받아 파싱
public static String find(String s, int p, int l, List<String> v, int[] n) {
    HttpURLConnection con = null;
    try {
        URL url = new URL(
        "http://openapi.epost.go.kr/postal/retrieveNewAdressAreaCdSearchAllService/..."
        + "?ServiceKey=서비스키"
        + "&countPerPage=" + l
        + "&currentPage=" + p
        + "&srchwrd=" + URLEncoder.encode(s,"UTF-8") // 검색어
        );
 
        con = (HttpURLConnection) url.openConnection();
        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(con.getInputStream());
 
        // ... XML 응답에서 에러 및 성공 여부 처리 ...
 
        if (bOk) { // 응답이 성공적일 경우
            NodeList ns = doc.getElementsByTagName("newAddressListAreaCdSearchAll");
            for (p = 0; p < ns.getLength(); p++) {
                for (nd = ns.item(p).getFirstChild(); nd != null; nd = nd.getNextSibling()) {
                    // "zipNo"(우편번호), "lnmAdres"(도로명주소) 등의 정보를
                    // 파싱하여 결과 리스트 'v'에 추가
                    v.add(nd.getTextContent());
                }
            }
        }
        // ...
    } catch (Exception e) {
        s = e.getMessage();
    }
    // ...
    return s;
}

4. SMTP를 이용한 이메일 전송 (NaverMailSender.java)

// Naver SMTP 서버와 javax.mail API를 사용하여 이메일을 전송하는 기능
// '비밀번호 찾기' 기능에 사용됩니다.
public void sendMail(String to, String subject, String body) throws MessagingException {
    // 1. SMTP 서버 정보(호스트, 포트, 인증 등)를 Properties에 설정
    Properties properties = new Properties();
    properties.put("mail.smtp.host", "smtp.naver.com");
    properties.put("mail.smtp.port", 465);
    properties.put("mail.smtp.auth", "true");
    properties.put("mail.smtp.ssl.enable", "true");
    properties.put("mail.smtp.ssl.trust", "smtp.naver.com");
 
    // 2. 이메일 계정 정보로 인증 세션 생성
    Session session = Session.getInstance(properties, new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(username, password); // 네이버 아이디, 앱 비밀번호
        }
    });
 
    // 3. 이메일 메시지(수신자, 제목, 본문) 생성
    Message message = new MimeMessage(session);
    message.setFrom(new InternetAddress(username));
    message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
    message.setSubject(subject);
    message.setText(body);
 
    // 4. 이메일 전송
    Transport.send(message);
}

프로젝트 성과

기술적 성장

  • 네트워크 프로그래밍: 순수 Java 소켓 및 멀티 스레딩 기반 C/S 아키텍처 심층 이해 및 실시간 통신 앱 구축.
  • 고급 GUI 프로그래밍: paintComponent 오버라이드를 통한 커스텀 UI 렌더링 및 GUI 동작 원리 파악.
  • 데이터베이스 설계 및 관리: ERD 설계, Soft-delete 구현을 통한 데이터 무결성 및 관리 방안 학습.
  • 전체 시스템 설계: 인증, 로비, 게임, 채팅, 관리 등 풀스택 애플리케이션 설계 및 구현 경험.

문제 해결 경험

  • 동시성 문제 해결: 공유 자원에 대한 synchronized 키워드 사용으로 스레드 안전성(Thread-safe) 확보.
  • 복잡한 상태 관리: 게임 중 플레이어 퇴장, 준비 상태 등 복잡한 비즈니스 로직의 안정적 구현.
  • 커스텀 프로토콜 정의: 명확한 구분자를 사용한 자체 프로토콜 설계로 통신 안정성 및 확장성 확보.

개선할 부분

현재의 Java Swing 기반 GUI를 JavaFX와 같은 더 현대적인 데스크톱 GUI 프레임워크로 교체하여, 백엔드는 그대로 유지하면서 보다 현대적인 UI/UX를 갖춘 애플리케이션으로 고도화해보고 싶습니다. 또한, 서버의 확장성과 부하 분산을 고려하여 Netty와 같은 고성능 비동기 이벤트 기반 프레임워크 도입을 검토해 볼 수 있습니다.

프로젝트 회고

이 프로젝트는 Java라는 하나의 언어만으로 네트워크 통신, 데이터베이스 연동, 그래픽 UI까지 모든 것을 만들어 볼 수 있었던 귀중한 경험이었습니다. 특히 라이브러리나 프레임워크의 도움 없이 직접 멀티 스레딩 서버와 커스텀 Swing 컴포넌트를 구현하며 컴퓨터 공학의 기본 원리를 몸으로 체득할 수 있었던 점이 가장 큰 성과라고 생각합니다.

프로젝트를 진행하며 마주친 여러 설계적 고민과 이를 해결해나가는 과정 자체가 중요한 학습의 기회가 되었습니다.

다른 프로젝트 둘러보기

다음 프로젝트텅장수강러