Skip to content

hellonayeon/java-chat

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

19 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

μžλ°” μ±„νŒ… ν”„λ‘œκ·Έλž¨

Java Swing ν™˜κ²½μ˜ ν…μŠ€νŠΈ μ±„νŒ… μ• ν”Œλ¦¬μΌ€μ΄μ…˜μœΌλ‘œ, Socket 톡신과 Multi Thread ν”„λ‘œκ·Έλž˜λ°μœΌλ‘œ κ΅¬ν˜„ν•œ ν”„λ‘œκ·Έλž¨

λͺ©μ°¨

개발 ν™˜κ²½ 및 μ‚¬μš© 기술

  • 개발 ν™˜κ²½
    • macOS Monterey 12.4
    • IntelliJ IDEA
    • Java 11
  • μ‚¬μš© 기술
    • Java Network Socket
    • AWT, Swing

μ‹€ν–‰ν™”λ©΄κ³Ό κΈ°λŠ₯μ„€λͺ…

  • 둜그인 ν™”λ©΄

    • μ‚¬μš©μž 아이디와 이름을 μž…λ ₯ν•˜λŠ” ν™”λ©΄
    • μ‚¬μš©μž 아이디: ν”„λ‘œκ·Έλž¨ λ‚΄λΆ€μ—μ„œ μ‚¬μš©μžλ₯Ό μ‹λ³„ν•˜λŠ” 데이터
    • 이름: μ‚¬μš©μž λͺ©λ‘κ³Ό μ±„νŒ…μ„ μž…λ ₯ν•œ μ‚¬λžŒμ„ ν‘œμ‹œν•˜λŠ” 데이터


  • λ‘œλΉ„ ν™”λ©΄

    • λ‘œλΉ„ μ±„νŒ… (λͺ¨λ“  μ‚¬μš©μž μ±„νŒ… κ°€λŠ₯)
    • μ±„νŒ… ν”„λ‘œκ·Έλž¨μ— μ ‘μ†ν•œ λͺ¨λ“  μ‚¬μš©μž 리슀트 좜λ ₯
    • μ±„νŒ…λ°© λͺ©λ‘ 좜λ ₯


  • μ±„νŒ…λ°© 생성 ν™”λ©΄

    • μ±„νŒ…λ°© 이름 μž…λ ₯

    • 확인 λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ μž…λ ₯ν•œ λ¬Έμžμ—΄μ„ λ°”νƒ•μœΌλ‘œ μƒˆλ‘œμš΄ μ±„νŒ…λ°© 생성

      • μƒˆλ‘œμš΄ μ±„νŒ… ν™”λ©΄ 좜λ ₯


      • μƒμ„±λœ μ±„νŒ…λ°© λͺ©λ‘λ“€μ€ λ‘œλΉ„μ—μ„œ 확인 κ°€λŠ₯



      • μ±„νŒ…λ°© λͺ©λ‘μ—μ„œ μ±„νŒ…λ°© 이름 클릭 ν•˜λ©΄, ν•΄λ‹Ή μ±„νŒ… ν™”λ©΄ 좜λ ₯



  • μ±„νŒ…λ°© ν™”λ©΄

    • ν•΄λ‹Ή μ±„νŒ…λ°©μ— μ ‘μ†ν•œ μ‚¬μš©μž λͺ©λ‘ 좜λ ₯



    • λ‚˜κ°€κΈ° λ²„νŠΌ 클릭 ν•˜λ©΄ μ±„νŒ…μ°½μ— 퇴μž₯ λ©”μ‹œμ§€ 좜λ ₯되고, μ‚¬μš©μž λͺ©λ‘ κ°±μ‹ 



    • λͺ¨λ“  μ‚¬μš©μžκ°€ μ±„νŒ…λ°©μ—μ„œ λ‚˜κ°„ 경우, μ±„νŒ…λ°© 이름을 λ‘œλΉ„μ˜ μ±„νŒ… λͺ©λ‘μ—μ„œ 제거

      • μ±„νŒ…λ°© 이름1 λͺ©λ‘μ—μ„œ 제거



    • 이미 μ—΄λ €μžˆλŠ” μ±„νŒ…λ°©μ„ λ‹€μ‹œ λ“€μ–΄κ°€λ € ν•  경우 였λ₯˜ νŒμ—… 좜λ ₯



κ΅¬ν˜„ 방식

  • μ„œλ²„μ™€ ν΄λΌμ΄μ–ΈνŠΈλŠ” Socket 으둜 톡신

  • ν΄λΌμ΄μ–ΈνŠΈ

    • Swing 을 μ΄μš©ν•΄ 화면을 ꡬ성
    • Thread λ₯Ό μ΄μš©ν•΄ μžμ‹ μ˜ Socket InputSream 을 μ§€μ†μ μœΌλ‘œ μ½μ–΄μ™€μ„œ μ„œλ²„μ—μ„œ 보낸 λ©”μ‹œμ§€λ₯Ό μˆ˜μ‹ 
  • μ„œλ²„

    • 각 ν΄λΌμ΄μ–ΈνŠΈμ— λŒ€ν•œ Socket 을 Multi Thread ν™˜κ²½μœΌλ‘œ 관리
    • Multi Thread λ₯Ό μ΄μš©ν•΄ λͺ¨λ“  μ‚¬μš©μžλ“€μ˜ Socket InputSream 을 μ§€μ†μ μœΌλ‘œ 확인
    • ν΄λΌμ΄μ–ΈνŠΈκ°€ 보낸 λ©”μ‹œμ§€λ₯Ό λ°”νƒ•μœΌλ‘œ μ„œλ²„μ— μ €μž₯된 자료ꡬ쑰λ₯Ό μ²˜λ¦¬ν•˜κ³ , 응닡을 전솑
  • ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„λŠ” λ¬Έμžμ—΄ λ©”μ‹œμ§€λ₯Ό μ£Όκ³  λ°›μœΌλ©°, μ£Όκ³  λ°›λŠ” μžλ£Œκ΅¬μ‘°λŠ” ν˜•μ‹μ— 따라 λͺ¨λ‘ λ¬Έμžμ—΄λ‘œ μΉ˜ν™˜

    • μ–‘μͺ½μ—μ„œ λ™μΌν•œ Request Response DTO λ₯Ό κ°€μ§€κ³  μžˆμ§€λ§Œ ν΄λΌμ΄μ–ΈνŠΈμ˜ 경우 Request DTO βž” String 으둜 λ³€κ²½ν•΄μ„œ μ†‘μ‹ ν•˜κ³ ,

      μ„œλ²„λŠ” 이λ₯Ό λ°›μ•„ νŒŒμ‹±ν•˜μ—¬ String βž” Request DTO λ₯Ό 생성해 μ‚¬μš©

      μ„œλ²„λ„ λ§ˆμ°¬κ°€μ§€λ‘œ ν΄λΌμ΄μ–ΈνŠΈλ‘œ λ©”μ‹œμ§€λ₯Ό 보낼 경우 Response DTO 객체λ₯Ό 생성해 전달할 λ‚΄μš©μœΌλ‘œ μΈμŠ€ν„΄μŠ€λ₯Ό μ΄ˆκΈ°ν™”ν•˜κ³ 

      Response DTO βž” String 으둜 λ³€κ²½ν•΄ ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ 전솑

      ν΄λΌμ΄μ–ΈνŠΈλŠ” 이λ₯Ό λ°›μ•„ νŒŒμ‹±ν•˜μ—¬ String βž” Response DTO λ₯Ό 생성해 μ‚¬μš©

    • Request DTO : ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλ²„μ— λ³΄λ‚΄λŠ” λ©”μ‹œμ§€ (객체 λ‚΄μš©μ„ λ¬Έμžμ—΄λ‘œ 생성)

    • Response DTO: μ„œλ²„κ°€ μ‚¬μš©μžμ—κ²Œ λ³΄λ‚΄λŠ” λ©”μ‹œμ§€ (객체 λ‚΄μš©μ„ λ¬Έμžμ—΄λ‘œ 생성)

      • 흐름도



      • νŒŒμ‹± 데이터 ν…Œμ΄λΈ”

        DtoType:data ν˜•μ‹μ˜ λ¬Έμžμ—΄λ‘œ λ©”μ‹œμ§€ μ†‘μˆ˜μ‹ 

        Request 의 전솑 μ£Όμ²΄λŠ” Client, Response 의 전솑 μ£Όμ²΄λŠ” Server



      • DtoType 에 따라 λ©”μ‹œμ§€ μ†‘μˆ˜μ‹ λΆ€μ—μ„œ λΆ„κΈ° 처리

          class enum DtoType {
            	INIT, // 둜그인 ν›„ 초기 데이터 전솑 κ΄€λ ¨ λ©”μ‹œμ§€ (μ‚¬μš©μž 리슀트, μ±„νŒ…λ°© 리슀트)
          
              LOGIN, // 둜그인 λ©”μ‹œμ§€ (μ‚¬μš©μž 생성, λ¦¬μŠ€νŠΈμ— μΆ”κ°€)
              CREATE_CHAT, // μƒˆλ‘œμš΄ μ±„νŒ…λ°© 생성 λ©”μ‹œμ§€
              ENTER_CHAT, EXIT_CHAT, // μ±„νŒ…λ°© μž…μž₯, 퇴μž₯ λ©”μ‹œμ§€
              MESSAGE, // μ±„νŒ… λ©”μ‹œμ§€
          
              USER_LIST, CHAT_ROOM_LIST, // μ‚¬μš©μž 리슀트, μ±„νŒ…λ°© 리슀트 λ©”μ‹œμ§€
          }
        class DTO {
          	DtoType type;
        
            public DTO(DtoType type) {
                this.type = type;
            }
        
            public DtoType getType() {
                return type;
            }
        
            @Override
            public String toString() {
                return type + ":";
            }
        }
      • μ˜ˆμ‹œ μ½”λ“œ

          /* Client Request */
          
          // Client Application
          public class LoginRequest extends DTO {
          
              String id;
          
              String name;
          
              public LoginRequest(String id, String name) {
                  super(DtoType.LOGIN);
          
                  this.id = id;
                  this.name = name;
              }
          
            	// 데이터 보낼 λ•Œ 객체 λ‚΄μš©μ„ λ°”νƒ•μœΌλ‘œ λ¬Έμžμ—΄λ‘œ λ°”κΏ”μ„œ 전솑
              @Override
              public String toString() {
                  return super.toString() + id + "," + name;
              }
          }
          
          // Server Application
          public class LoginRequest {
          
              String id;
          
              String name;
          
            	// 슀트링 λ©”μ‹œμ§€λ‘œ μˆ˜μ‹ ν•œ λ‚΄μš©μ„ 객체둜 νŒŒμ‹±ν•΄μ„œ μ‚¬μš©
              public LoginRequest(String message) {
                  String[] value = message.split(",");
                  id = value[0];
                  name = value[1];
              }
          
              public String getId() {
                  return id;
              }
          
              public String getName() {
                  return name;
              }
          }		
        /* Server Response */
        
        // Server Application
        public class ChatRoomListResponse extends DTO {
        
            List<ChatRoom> chatRooms;
        
            public ChatRoomListResponse(List<ChatRoom> chatRooms) {
                super(DtoType.CHAT_ROOM_LIST);
        
                this.chatRooms = chatRooms;
            }
        
          	// Object to String
            @Override
            public String toString() {
                String str = super.toString();
        
                for (ChatRoom chatRoom : chatRooms) {
                    str += chatRoom.getName() + ",";
                }
                return (chatRooms.size() > 0) ? str.substring(0, str.length() - 1) : str + "empty";
            }
        }
        
        // Client Application
        public class ChatRoomListResponse {
        
            List<ChatRoom> chatRooms = new ArrayList<>();
        
          	// String to Object
            public ChatRoomListResponse(String message) {
                if (!message.equals("empty")) {
                    String[] names = message.split(",");
                    for(String name : names) {
                        chatRooms.add(new ChatRoom(name));
                    }
                }
            }
        
            public List<ChatRoom> getChatRooms() {
                return chatRooms;
            }
        }

μ„œλ²„ μ• ν”Œλ¦¬μΌ€μ΄μ…˜

  • 클래슀 멀버

    class Application {
      
      public static List<Sockets> sockets; // ν΄λΌμ΄μ–ΈνŠΈ μ†ŒμΌ“ 리슀트
    
      ChatService chatService; // μ±„νŒ… 데이터 처리 μΈμŠ€ν„΄μŠ€ (ServerThread μΈμŠ€ν„΄μŠ€ 생성 μ‹œ νŒŒλΌλ―Έν„°λ‘œ 전달)
    
      ChatDao chatDao; // μ±„νŒ… 데이터 관리 μΈμŠ€ν„΄μŠ€ (ChatService μΈμŠ€ν„΄μŠ€ 생성 μ‹œ νŒŒλΌλ―Έν„°λ‘œ 전달)
      
    }
    
    βž” Application μΈμŠ€ν„΄μŠ€λŠ” main ν•¨μˆ˜ μ‹€ν–‰ μ‹œ ν•œ 번만 μƒμ„±ν•˜λ―€λ‘œ, μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ‚¬μš©ν•˜λŠ” μΈμŠ€ν„΄μŠ€λ“€μ„ μƒμ„±ν•΄μ£ΌλŠ” μ—­ν• 
      
    βž” Application μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈλ“€μ˜ Socket 연결을 λŒ€κΈ°ν•˜λ©° 톡신을 μœ„ν•œ μ†ŒμΌ“μ„ μƒμ„±ν•˜λ―€λ‘œ Socket List 도 ν•¨κ»˜ 관리
      
    
    
    class ServerThread {
      
      Socket socket; // ν΄λΌμ΄μ–ΈνŠΈ μ†ŒμΌ“
    
    	ChatService chatService;
      
    }
    βž” 각 ν΄λΌμ΄μ–ΈνŠΈλ§ˆλ‹€ ServerThread μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό λ™μž‘μ‹œμΌœ λ©”μ‹œμ§€ μˆ˜μ‹ 
    
      
    class User {
      
      String id; // 아이디
    
      String name; // 이름
    
      Socket socket; // μžμ‹ μ˜ μ†ŒμΌ“ (ν΄λΌμ΄μ–ΈνŠΈ μ†ŒμΌ“)
      
    }
    βž” μ‚¬μš©μž ν΄λž˜μŠ€λŠ” μžμ‹ μ˜ μ†ŒμΌ“ 정보λ₯Ό μ €μž₯
    
    βž” μ‚¬μš©μž μΈμŠ€ν„΄μŠ€λ₯Ό μ±„νŒ…λ°© μ‚¬μš©μž λ¦¬μŠ€νŠΈμ— μΆ”κ°€/μ‚­μ œν•˜λ©° λ©”μ‹œμ§€ 솑신 관리
    
      
    class ChatRoom {
      
      String name; // μ±„νŒ…λͺ…
    
    	List<User> users; // μ±„νŒ…λ°© λ‚΄μ˜ μ‚¬μš©μž 리슀트
      
    }
    βž” μ±„νŒ…λ°© μž…μž₯/퇴μž₯에 따라 μ‚¬μš©μž λ¦¬μŠ€νŠΈμ— User μΈμŠ€ν„΄μŠ€λ₯Ό μ‚½μž… λ˜λŠ” μ‚­μ œ
      
    βž” 각 μ±„νŒ…λ°©μ— κ΄€λ¦¬λ˜κ³ μžˆλŠ” μ‚¬μš©μž 리슀트λ₯Ό λ°”νƒ•μœΌλ‘œ μ„œλ²„μ—μ„œ λ©”μ‹œμ§€ 솑신
    
    βž” User μΈμŠ€ν„΄μŠ€ μ•ˆμ— Socket 정보가 μžˆμœΌλ―€λ‘œ κ°œλ³„μ μΈ μ±„νŒ…λ°© μ²˜λ¦¬κ°€ κ°€λŠ₯
      
      
      
    class ChatService {
      
      ChatDao chatDao;
      
    }
    βž” DAO μ—μ„œ μ œκ³΅ν•˜λŠ” λ©”μ„œλ“œλ₯Ό μ΄μš©ν•΄, μ±„νŒ… ν”„λ‘œκ·Έλž¨μ—μ„œ μ‚¬μš©ν•˜λŠ” 데이터λ₯Ό κ°€μ Έμ™€μ„œ 처리
      
    
    class ChatDao {
      
      List<User> users; // 접속 쀑인 λͺ¨λ“  μ‚¬μš©μž 리슀트
    
      List<ChatRoom> chatRooms;
    
      ChatRoom lobby; // λ‘œλΉ„ μ±„νŒ…λ°© 정보 (λ‘œλΉ„λ₯Ό 계속 거쳐 λ‹€λ‹ˆλ‹ˆ λ‘œλΉ„ 정보 μ €μž₯)
    
      String LOBBY_CHAT_NAME = "Lobby";
      
    }
    βž” ChatService μΈμŠ€ν„΄μŠ€μ—μ„œ μš”μ²­ν•˜λŠ” μ±„νŒ… 데이터λ₯Ό 제곡
      
    βž” λ‹€λ₯Έ μ±„νŒ…λ°©μ— λ“€μ–΄κ°€ μžˆμ–΄λ„ λ‘œλΉ„ μ±„νŒ…λ°©μ€ 계속 κ°±μ‹ ν•˜κΈ° μœ„ν•΄ lobby 둜 λ”°λ‘œ 관리
  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜ ꡬ쑰

    • 클래슀 λ‹€μ΄μ–΄κ·Έλž¨


  • μΈμŠ€ν„΄μŠ€ λ‹€μ΄μ–΄κ·Έλž¨

    • ν΄λΌμ΄μ–ΈνŠΈ μ†ŒμΌ“ μ—°κ²°



    • μ‚¬μš©μž 정보 생성 (아이디, 이름 μž…λ ₯ ν›„)



    • μƒˆλ‘œμš΄ μ±„νŒ…λ°© 생성



​

​

ν΄λΌμ΄μ–ΈνŠΈ μ• ν”Œλ¦¬μΌ€μ΄μ…˜

  • 클래슀 멀버

    class Application {
      
        public static Socket socket;
    
        public static MessageSender sender;
    
        public static MessageReceiver receiver;
    
        public static LobbyFrame lobbyFrame;
    
        public static User me;
    
        public static List<User> users = new ArrayList<>(); // ν˜„μž¬ 접속 쀑인 λͺ¨λ“  μ‚¬μš©μž 리슀트
    
        public static List<ChatRoom> chatRooms = new ArrayList<>(); 
    
      	// μ±„νŒ…λ°© ν”„λ ˆμž„ 관리, λ©”μ‹œμ§€ 왔을 λ•Œ μ–΄λ–€ μ±„νŒ…λ°© λ ˆμ΄λΈ”μ„ κ°±μ‹ ν•΄μ•Ό ν•˜λŠ”μ§€ 확인
      	// [key] μ±„νŒ…λ°© 이름
        public static Map<String, ChatPanel> chatPanelMap = new HashMap<>();
    
        public static Map<String, ChatRoomUserListPanel> chatRoomUserListPanelMap = new HashMap<>();
    
        public static final String LOBBY_CHAT_NAME = "Lobby"; // λ‘œλΉ„ μ±„νŒ…λ°© 이름
    
    }
    βž” μ„œλ²„μ™€ μ†ŒμΌ“ μ—°κ²° ν›„ μ†ŒμΌ“ 정보λ₯Ό μ €μž₯ν•˜κ³  관리
      
    βž” 주기적으둜 μ†ŒμΌ“ λ©”μ‹œμ§€λ₯Ό 읽기 μœ„ν•œ μŠ€λ ˆλ“œ 생성
    
      
      
    class MessageReader {
      
      Socket socket;
      
    }
    
    class MessageSender {
      
      Socekt socket;
      
    }
  • ν™”λ©΄ ν”„λ ˆμž„



About

πŸ“’ μžλ°” μ±„νŒ… ν”„λ‘œκ·Έλž¨ (Socket + Multi Thread + Swing)

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages