-
[몰입형] 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