ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [몰입형] Multicast
    몰입형 2022. 9. 6. 16:37

    Multicast

    멀티캐스트(multicast)한 번의 송신으로 메시지나 정보를 목표한 여러 컴퓨터에 동시에 전송하는 것을 말한다. 

    다음은 자바 Swing을 이용하여 디자인 하고, 멀티캐스를 구현한 채팅 서비스이다.

     

    기능

    1. 로그인 - 닉네임 입력 확인, 특수문자 포함 불가능

    2. 채팅창

    - 귓속말

    - 강퇴하기

    - 채팅 입력 시간 표시

    -  비속어 사용시 5초간 채팅 금지

    - 비속어 필터링

    - 채팅방 색상(다크모드, 라이트모드)

    닉네임을 아무것도 입력하지 않고 로그인을 시도하면 알림창이 뜸

     

    특수문자가 포함된 닉네임은 사용할 수 없음

     

    사용자 목록 클릭시 귓속말이나 강퇴를 할 수 있음

     

    자기 자신에게 귓속말을 보내거나 강퇴할 수 없음

     

    귓속말을 보낸 상대에게만 메세지가 보임

     

    강퇴하기를 누를 경우 알림창이 뜨고 예를 누르면

     

    추방당했다는 메세지와 함께 aaa는 사용자 목록에서 제외됨

     

    다크모드와 라이트모드를 선택할 수 있음
    비속어 입력
    경고 알림창
    5초간 채팅을 보낼 수 없으며 비속어는 필터링되어 표시

    package Multicast;
    import java.io.*;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import java.net.*;
    class ReceiverThread extends Thread {
        Socket socket;
        SenderThread send;
        String name;
        ReceiverThread(Socket socket, SenderThread send, String name) {
            this.socket = socket;
            this.send = send;
            this.name = name;
        }
        public void run() {
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while (true) {
                    Date now = new Date(System.currentTimeMillis());
                    SimpleDateFormat simple= new SimpleDateFormat("(a hh:mm)");
    
          //서버로부터 수신된 메시지를 모니터로 출력
                    String str = reader.readLine();
                    if (str == null) 
                       break;
                    if(str.contains("#")) {
                       String newStr = str.replace("#", "");
                       send.area.append(newStr+simple.format(now));
                       send.area.append("\n");
                       if(str.contains("님이 나가셨습니다")) {
                          String[] strArr = str.split("#");
                          send.arr.removeElement(strArr[1]);
                       }else if(str.contains("#kick")) {
                          String[] strArr = str.split("#");
                          if(name.equals(strArr[2])) {
                             send.sendMsg("#redCard");
                             System.exit(0); 
                          }
                       }else if(str.contains("님이 추방당하셧습니다")) {
                          String[] strArr = str.split("#");
                          send.arr.removeElement(strArr[1]);
                       }
                    }else if(str.contains("->")) {   // 귓속말
                        String[] whisper = str.split("->");
                        if(whisper[1].equals(name)) {
                           send.area.append(whisper[0].replace(">", "(귓)>") + whisper[2]);
                           send.area.append("\n");
                        }else if(whisper[0].equals(name+">")) {
                           send.area.append(whisper[1]+"(에게)>" + whisper[2]);
                           send.area.append("\n");
                        }
                     }else if(!str.contains(">")) {
                       if(str.contains("&")) {
                          String[] strArr = str.split("&");
                          System.out.println(strArr.length);
                          send.arr.clear();
                          for(int i = 0; i < strArr.length; i++) {
                             if(strArr[i].equals(name)) {
                                send.arr.addElement(strArr[i] + "(나)");
                             }else {
                                send.arr.addElement(strArr[i]);
                             }
                          }
                       }
                    }else {
                       String[] strArr = str.split(">");
                       if(strArr[0].equals(name)) {
                          str = strArr[0] + "(나)>" + strArr[1];
                          send.area.append(str);
                            send.area.append("\n");
                       }else {
                    	send.area.append(str);
                        send.area.append("\n");}
                    }
                    System.out.println(str+simple.format(now));
                }
            }
            catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }​

     

    package Multicast;
    
    import java.net.*;
    class ServerExample4 {
        public static void main(String[] args) {
            ServerSocket serverSocket = null;
            try {
                serverSocket = new ServerSocket(9002);
                while (true) {
                    Socket socket = serverSocket.accept();
                    Thread thread = new PerClinetThread(socket);
                    thread.start();
                }
            }
            catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }
    package Multicast;
    //각 클라이언트 접속에 대해 하나씩 작동하는 스레드 클래스 
    import java.io.*;
    import java.net.*;
    import java.util.*;
    class PerClinetThread extends Thread {
     
      // ArrayList 객체를 여러 스레드가 안전하게 공유할 수 있는 동기화된 리스트로 만듭니다.
      static List<PrintWriter> list = Collections.synchronizedList(new ArrayList<PrintWriter>());
      static ArrayList<String> nameList = new ArrayList<String>();
      Socket socket;
      PrintWriter writer;
      boolean kicked=false;
      PerClinetThread(Socket socket) {
          this.socket= socket;
          try {
              writer = new PrintWriter(socket.getOutputStream());
              list.add(writer);
          }
          catch (Exception e) {
              System.out.println(e.getMessage());
          }
      }
      public void run() {
          String name = null;
          try {
              BufferedReader reader = new BufferedReader(
                  new InputStreamReader(socket.getInputStream()));
         
              // 수신된 첫번째 문자열을 대화명으로 사용하기 위해 저장
              name = reader.readLine(); 
              nameList.add(name);
              
              sendAll("#" + name + "#님이 들어오셨습니다");
              while (true) {
                 String nameStr = "";
                  for(int i = 0; i < nameList.size(); i++) {
                     nameStr += nameList.get(i) + "&";
                  }
                  sendAll(nameStr);
                  String str = reader.readLine();
                  if (str == null)
                      break;
                  if (str.contains("#kick")) {
                     String[] strArr = str.split("#");
                     sendAll("#kick"+name+"님이#" +strArr[2]+"#님을 추방하였습니다");
                  }else if (str.contains("#redCard")) {   
                     kicked=true;
                  }else {
                	  sendAll(name + ">" + str);  // 수신된 메시지 앞에 대화명을 붙여서 모든 클라이언트로 송신}
                  }
              }
          }
          catch (Exception e) {
              System.out.println(e.getMessage());
          }
          finally {
             if(kicked == true) {
                  list.remove(writer);
                  nameList.remove(name);
                  sendAll("#" + name + "#님이 추방당하셧습니다"); // 사용자가 채팅을 종료했다는 메시지를 모든 클라이언트로 보냅니다.
                  try {
                      socket.close();
                  }
                  catch (Exception ignored) {
                  }
             }else {
                  list.remove(writer);
                  nameList.remove(name);
                  sendAll("#" + name + "#님이 나가셨습니다"); // 사용자가 채팅을 종료했다는 메시지를 모든 클라이언트로 보냅니다.
                  try {
                      socket.close();
                  }
                  catch (Exception ignored) {
                  }
             }
          }
      }
     
      // 서버에 연결되어 있는 모든 클라이언트로 똑같은 메시지를 보냅니다.
      private void sendAll(String str) {  
          for (PrintWriter writer : list) {
              writer.println(str);
              writer.flush();
          }
      }
    }
    package Multicast;
    
    import java.net.*;
    class ClientExample4 {
        public static void start(String name) {
        	try {
        	    // 서버와 연결
                    Socket socket = new Socket("127.0.0.1", 9002);
                     // 메시지 송신 쓰레드와 수신 쓰레드 생성해서 시작
                    SenderThread thread1 = new SenderThread(socket, name);
                    Thread thread2 = new ReceiverThread(socket, thread1, name); 
                    
                    thread1.start();
                    thread2.start();
                }
                catch (Exception e) {
                    System.out.println(e.getMessage());
                }
        }
    }
    package Multicast;
    
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    
    public class Login {
    	static JTextField text;
    	static JFrame frame;
    	public static void login() {
        	frame = new JFrame("Login");
        	frame.setBounds(400, 300, 400, 240);
        	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        	frame.setLayout(new BorderLayout());// 동,서,남,븍 나뉨
        	frame.setResizable(false); 	// 크기 고정
        	
        	JPanel panel = new JPanel();
        	panel.setLayout(null);
        	
        	JLabel la = new JLabel("닉네임");
        	la.setBounds(65, 70, 80, 35);	// x, y, width, height
        	panel.add(la);
        	
        	text = new JTextField();
        	text.setBounds(125, 73, 160, 30);
        	text.addKeyListener(new KeyAdapter() {
                public void keyPressed(KeyEvent e) {
                   if(e.getKeyCode()==KeyEvent.VK_ENTER) {//엔터키 누를시
                      action();
                   }
                }
             });
        	panel.add(text);
        	
        	JButton btn = new JButton("로그인");
        	btn.setBackground(Color.lightGray);
        	btn.setBounds(125, 110, 160, 30);
        	Font font = new Font("맑은 고딕", Font.BOLD, 10);
        	btn.setFont(font);
        	btn.addActionListener(new ActionListener() {
        		@Override
        		public void actionPerformed(ActionEvent e) {
        			if(e.getActionCommand().equals("로그인")) {
        				action();
        			}
        		}
        	});
        	
        	panel.add(btn);
        	
        	frame.setContentPane(panel);
        	frame.setVisible(true);
        }
    	
    	public static void action() {
    		String[] chars = new String[] {"~", "`", "!", "@", "#", "$", "%", "^",
    				  "&", "*", "(", ")", "-", "_", "+",
    				  "=", "'", "<", ">", "?", "/", ";", ":", "|"};
    		String name = text.getText();
    		if(name.length() < 1) {
    			JOptionPane.showMessageDialog(null,"닉네임을 입력해주세요");
    		}else{
    			int cnt = 0;
    			for(int i = 0; i < chars.length; i++) {
    				if(name.contains(chars[i])) {
    					cnt++;
    				}
    			}
    			if(cnt > 0) {
    				JOptionPane.showMessageDialog(null,"특수문자는 포함하실 수 없습니다");
    			}else {
    				frame.setVisible(false);
    				ClientExample4.start(name);
    			}
    		}
    	}
    	
    	
        public static void main(String[] args) {
            if (args.length != 1) {
            	login();
            }
        }
    }
    package Multicast;
    import java.io.*;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import java.net.*;
    class ReceiverThread extends Thread {
        Socket socket;
        SenderThread send;
        String name;
        ReceiverThread(Socket socket, SenderThread send, String name) {
            this.socket = socket;
            this.send = send;
            this.name = name;
        }
        public void run() {
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while (true) {
                    Date now = new Date(System.currentTimeMillis());
                    SimpleDateFormat simple= new SimpleDateFormat("(a hh:mm)");
    
          //서버로부터 수신된 메시지를 모니터로 출력
                    String str = reader.readLine();
                    if (str == null) 
                       break;
                    if(str.contains("#")) {
                       String newStr = str.replace("#", "");
                       send.area.append(newStr+simple.format(now));
                       send.area.append("\n");
                       if(str.contains("님이 나가셨습니다")) {
                          String[] strArr = str.split("#");
                          send.arr.removeElement(strArr[1]);
                       }else if(str.contains("#kick")) {
                          String[] strArr = str.split("#");
                          if(name.equals(strArr[2])) {
                             send.sendMsg("#redCard");
                             System.exit(0); 
                          }
                       }else if(str.contains("님이 추방당하셧습니다")) {
                          String[] strArr = str.split("#");
                          send.arr.removeElement(strArr[1]);
                       }
                    }else if(str.contains("->")) {   // 귓속말
                        String[] whisper = str.split("->");
                        if(whisper[1].equals(name)) {
                           send.area.append(whisper[0].replace(">", "(귓)>") + whisper[2]);
                           send.area.append("\n");
                        }else if(whisper[0].equals(name+">")) {
                           send.area.append(whisper[1]+"(에게)>" + whisper[2]);
                           send.area.append("\n");
                        }
                     }else if(!str.contains(">")) {
                       if(str.contains("&")) {
                          String[] strArr = str.split("&");
                          System.out.println(strArr.length);
                          send.arr.clear();
                          for(int i = 0; i < strArr.length; i++) {
                             if(strArr[i].equals(name)) {
                                send.arr.addElement(strArr[i] + "(나)");
                             }else {
                                send.arr.addElement(strArr[i]);
                             }
                          }
                       }
                    }else {
                       String[] strArr = str.split(">");
                       if(strArr[0].equals(name)) {
                          str = strArr[0] + "(나)>" + strArr[1];
                          send.area.append(str);
                            send.area.append("\n");
                       }else {
                    	send.area.append(str);
                        send.area.append("\n");}
                    }
                    System.out.println(str+simple.format(now));
                }
            }
            catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
    package Multicast;
    import java.net.*;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    
    import java.util.ArrayList;
    
    import javax.swing.*;
    import javax.swing.event.ListSelectionEvent;
    import javax.swing.event.ListSelectionListener;
    
    import java.awt.*;
    import java.awt.event.*;
    import java.io.*;
    class SenderThread extends Thread implements ActionListener{
        Socket socket;
        String name, whispering, my;
        PrintWriter writer;
        JTextField tf;
        JTextArea area = new JTextArea();
        DefaultListModel<String> arr = new DefaultListModel<>();
        JList list;
        JLabel peopleList, label;
        JFrame frame;
        String str = "";
        JButton btn3;
        SimpleDateFormat simple;
        Date now;
        JPanel panel;
        //JButton whbtn;
        SenderThread(){}
        
        SenderThread(Socket socket, String name) { 
            this.socket = socket;
            this.name = name;
            
            frame = new JFrame("Chat");
            frame.setBounds(400, 140, 600, 540);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setResizable(false);    // 크기 고정
           
            panel = new JPanel();
            panel.setLayout(null);
           
            // 채팅
            JScrollPane scrollPane = new JScrollPane(area);
            scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);   // 스크롤바 항상 보이게
            scrollPane.setBorder(null);
            scrollPane.setBounds(10, 10, 360, 440);
            panel.add(scrollPane);
            area.setEditable(false);
          
           // 사용자 목록
            label = new JLabel("사용자 목록");
            label.setBounds(440, 10, 80, 20);
            panel.add(label);
           
            list = new JList(arr);
            //list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
           
            list.addMouseListener(new MouseAdapter() {
               public void mouseClicked(MouseEvent e) {
                  if(list.getSelectedValue() !=null) {
                    System.out.println("d"+list.getSelectedValue());
                      JPopupMenu menu = new JPopupMenu();
                      JMenuItem whbtn  = new JMenuItem("귓속말");
                      whbtn.addActionListener(new ActionListener() {
                             public void actionPerformed(ActionEvent e) {
                                peopleList.setText(whispering + "에게");
                                tf.requestFocus();
                             }
                         });                  
                      
                      JMenuItem kick = new JMenuItem("강퇴하기");
                      kick.addActionListener(new ActionListener() {
                             public void actionPerformed(ActionEvent e) {
                               int result=JOptionPane.showConfirmDialog(null,"진짜로 강퇴하시겠습니까?","강퇴확인",JOptionPane.YES_NO_OPTION);
                              if(result==JOptionPane.YES_OPTION) {
                                   String kickCommand = "#kick#"+whispering;
                                  writer.println(kickCommand);
                                  writer.flush();
                              }else {
                                 JOptionPane.showMessageDialog(null,"취소하였습니다");
                              }
                               
                             }
                         });   
                      
                      menu.addSeparator();
                         menu.add(whbtn);
                         menu.add(kick);
                         menu.show(e.getComponent(),e.getX(),e.getY());
                  }
               }
           });
            list.addListSelectionListener(new ListSelectionListener() {
                @Override
                public void valueChanged(ListSelectionEvent e) {
                   whispering = (String) list.getSelectedValue();
                   if(whispering != null) {
                      // 자기 자신에게는 귓속말하지 못하도록함
                      if(whispering.equals(name+"(나)")) {
                         list.clearSelection();
                         whispering = null;
                         
                      }else {
    
                      }
                   }
                }
                 
              });
           
           JScrollPane scrollPane2 = new JScrollPane(list);
           scrollPane2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
           scrollPane2.setBorder(null);
           scrollPane2.setBounds(380, 35, 190, 385);
          panel.add(scrollPane2);
           peopleList = new JLabel("모두에게");
           peopleList.setBounds(10, 464, 50, 20);
           panel.add(peopleList);
           
           tf = new JTextField();
           tf.setBounds(70, 460, 200, 30);
           panel.add(tf);
           tf.addKeyListener(new KeyAdapter() {
             public void keyPressed(KeyEvent e) {
            	 	
                   now = new Date(System.currentTimeMillis());
                   simple= new SimpleDateFormat("(a hh:mm)");
                if(e.getKeyCode()==KeyEvent.VK_ENTER) {//엔터키 누를시
                	action(btn3);
                }
             }
          });
           
          JButton btn1 = new JButton("다크모드");
          btn1.setBounds(380, 425, 190, 30);
          btn1.setBackground(Color.lightGray);
          btn1.addActionListener(this);
           panel.add(btn1);
           
          btn3 = new JButton("보내기");
          btn3.setBounds(270, 460, 95, 30);
          btn3.setBackground(Color.lightGray);
          btn3.addActionListener(this);
          panel.add(btn3);
           
           JButton btn2 = new JButton("나가기");
          btn2.setBounds(380, 460, 190, 30);
          btn2.setBackground(Color.lightGray);
          btn2.addActionListener(this);
           panel.add(btn2);
           
           frame.setContentPane(panel);
           frame.setVisible(true);
        }
        public void run() {
           try {
                //BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                writer = new PrintWriter(socket.getOutputStream());
                
              // 제일 먼저 서버로 대화명 송신한다.
              writer.println(name);
               writer.flush();
               
               while (true) {
                   if (str.equals("bye"))
                       break;
               }
            }
            catch (Exception e) {
                System.out.println(e.getMessage());
            }
            finally {
                try { 
                    socket.close(); 
                } 
                catch (Exception ignored) {
                }
            }
        }
        
        public void action(JButton button) {
        	Timer timer = new Timer(5000, new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                	tf.setEnabled(true);
                	tf.requestFocus();
                    button.setEnabled(true);
                    button.setText("보내기");
                }
            });
        	timer.setRepeats(false);
        	String chat = tf.getText();
            if(chat.length() > 0) {
            	String[] chars = new String[] {"시발", "병신", "개새끼", "바보", "멍청이", "존나"};
            	int cnt = 0;
            	for(int i = 0; i < chars.length; i++) {
            		if(chat.contains(chars[i])) {
            			chat = chat.replace(chars[i], "*".repeat(chars[i].length()));
            			cnt++;
            		}
            	}
            	if(cnt > 0) {
            		tf.setEnabled(false);
            		button.setEnabled(false);
                	button.setText("채금");
                	timer.start();
                	JOptionPane.showMessageDialog(null,"비속어를 사용하셨습니다. 5초간 채팅 금지입니다.");
            	}
            	if(peopleList.getText().equals("모두에게")) {   // 귓속말 보내는중
                    String[] to = peopleList.getText().split("에게");
                    writer.println(chat+simple.format(now));
                    tf.setText("");
                     writer.flush();
                 }else {
                    String[] to = peopleList.getText().split("에게");
                    writer.println("->" + to[0] + "->" + chat+simple.format(now));
                    tf.setText("");
                    writer.flush();
                    peopleList.setText("모두에게");
                 }
            }
        }
        
    
       @Override
       public void actionPerformed(ActionEvent e) {
             now = new Date(System.currentTimeMillis());
             simple = new SimpleDateFormat("(a hh:mm)");
          if(e.getActionCommand().equals("보내기")) {
        	 JButton button = (JButton)e.getSource();
             action(button);
          }else if(e.getActionCommand().equals("다크모드")) {
              JButton btn = (JButton)e.getSource();
              area.setBackground(Color.DARK_GRAY);
              area.setForeground(Color.WHITE);
              list.setBackground(Color.DARK_GRAY);
              list.setForeground(Color.WHITE);
              panel.setBackground(Color.GRAY);
              tf.setBackground(Color.DARK_GRAY);
              tf.setForeground(Color.WHITE);
              label.setForeground(Color.white);
              peopleList.setForeground(Color.white);
              btn.setText("라이트 모드");
              
              }else if(e.getActionCommand().equals("라이트 모드")) {
                 JButton btn = (JButton)e.getSource();
                 area.setBackground(Color.WHITE);
                 area.setForeground(Color.BLACK);
                 list.setBackground(Color.WHITE);
                 list.setForeground(Color.BLACK);
                 panel.setBackground(new Color(238, 238, 238));
                 tf.setBackground(Color.WHITE);
                 tf.setForeground(Color.BLACK);
                 label.setForeground(Color.BLACK);
                 peopleList.setForeground(Color.BLACK);
                 btn.setText("다크모드");      
              }else if(e.getActionCommand().equals("나가기")) {
             //str = "bye";
             frame.dispose();
             System.exit(0);
          }
       }
       void sendMsg(String msg) {
          writer.println(msg);
          writer.flush();
       }
       
    }

     

    728x90

    '몰입형' 카테고리의 다른 글

    [몰입형] 쿠키와 세션  (0) 2022.09.03
    [몰입형] 절대경로와 상대경로  (0) 2022.09.03
    [몰입형] OSI 7계층  (0) 2022.09.03
    [몰입형] HTTP Method  (0) 2022.09.03
    [몰입형] Unicast(유니캐스트)  (0) 2022.09.03
Designed by Tistory.