개인공부/Java
java 소켓 멀티캐스트 && JFrame
- -
해당 닉네임을 사용하는 클라이언트가 서버에 접속 중일 경우 유효성 검사에 의해 접속 불가 처리를 구현하였습니다.
클라이언트가 필터링 단어를 지정하면 해당 단어는 특수문자 처리가 되는 것을 확인할 수 있습니다
귓속말할 대상의 대화명을 입력 후 대화 내용을 입력하면 그 클라이언트에게만 메시지를 전송한다
채팅방의 테마를 설정하는 기능을 구현 하였다
Client.java
package Multicast;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.Socket;
class ClientExample4 extends JFrame implements ActionListener {
CardLayout card = new CardLayout();
Login login = new Login();
WaitRoom wr = new WaitRoom();
FilterUi ui = new FilterUi();
public ClientExample4() {
setLayout(card);
add("LOGIN", login);
add("WR", wr);
setSize(1024, 950);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
login.b1.addActionListener(this);
login.b2.addActionListener(this);
wr.b3.addActionListener(this);//waitRoom에서 차단하기 버튼
wr.tf.addActionListener(this);
wr.b4.addActionListener(this);//waitRoom에서 필터링 추가하기 버튼
}
public static void main(String[] args) {
new ClientExample4();
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getSource());
if (e.getSource() == login.b1) {
String name = login.pf.getText();
String sex = "";
if (login.rb1.isSelected())
sex = "남자";
else
sex = "여자";
connection(name, sex);
}
}
private void connection(String name, String sex) {
try {
// 서버와 연결
Socket socket = new Socket("localhost", 9002);
Thread thread2 = new ReceiverThread(socket, wr, login, ui);
thread2.start();
Thread thread1 = new SenderThread(socket, name, sex, wr, login, ui);
thread1.start();
// card.show(getContentPane(), "WR");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
Client의 senderThread.java
package Multicast;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
class SenderThread extends Thread {
Socket socket;
String name, sex, pos;
WaitRoom wr;
PrintWriter writer;
Login login;
FilterUi ui;
public SenderThread(Socket socket, String name, String sex, WaitRoom wr, Login login, FilterUi ui) {
this.socket = socket;
this.name = name;
this.sex = sex;
this.wr = wr;
this.login = login;
this.ui = ui;
wr.tf.addKeyListener(new keyEventHandler());
wr.b6.addActionListener(new ActionHandler());//waitRoom에서 나가기 버튼
wr.b1.addActionListener(new ActionHandler());//waitRoom에서 추방건의 버튼
ui.tf.addKeyListener(new KeyEventHandler2());
wr.b5.addActionListener(new ActionHandler());
}
public void run() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
writer = new PrintWriter(socket.getOutputStream());
// 제일 먼저 서버로 대화명 송신한다.
writer.println(name + "##" + sex + "##");
writer.flush();
// 키보드로 입력된 메시지를 서버로 송신
while (true) {
String str = reader.readLine();
if ("/!".startsWith(str)) {
continue;
}
if (str.equals("bye"))
break;
writer.println(str);
writer.flush();
}
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
try {
socket.close();
} catch (Exception ignored) {
}
}
}
class keyEventHandler extends KeyAdapter {//이너클래스
@Override
public void keyPressed(KeyEvent e) {
// System.out.println("wr tf 이벤트 액션 start");
if (e.getKeyChar() == KeyEvent.VK_ENTER) {//엔터를 눌렀을 경우
String StateCode = "50";
System.out.println(StateCode + "##" + wr.tf.getText());
if ("/!".startsWith(wr.tf.getText())) {
} else {
writer.println(wr.tf.getText());
writer.flush();
wr.tf.setText("");
}
}
}
}
class KeyEventHandler2 extends KeyAdapter {
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
if (ui.tf.getText().length() < 2) {
System.out.println("두자리 이상만 가능");
} else {
ReceiverThread.addFilter(ui.tf.getText());
writer.println("/!" + ui.tf.getText() + "!/");
writer.flush();
ui.tf.setText("");
ui.disp();
}
}
}
}
class ActionHandler implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == wr.b6) {
writer.println("exit##");
writer.flush();
wr.ta.setText("");//textarea 초기화
wr.setVisible(false);
login.setVisible(true);
} else if (e.getSource() == wr.b6) {
String uname = JOptionPane.showInputDialog("건의할 대상자의 닉네임을 입력하세요");
writer.println("exP##uname");
writer.flush();
} else if (e.getSource() == wr.b5) {
String resultStr = null;
String totalStr = null;
resultStr = JOptionPane.showInputDialog("귓속말 할 대상을 입력해주세요.");
totalStr = JOptionPane.showInputDialog("내용을 입력하세요");
writer.println("Whispering##" + resultStr + "##" + totalStr);
writer.flush();
}
}
}
}
Client의 ReceiverThread.java
package Multicast;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
class ReceiverThread extends Thread {
Socket socket;
WaitRoom wr;
ArrayList<String> banName = new ArrayList<String>();
ActionEventEx block = new ActionEventEx();
Login login;
static ArrayList<String> filter = new ArrayList<String>();
FilterUi ui;
ReceiverThread(Socket socket, WaitRoom wr, Login login, FilterUi ui) {
this.socket = socket;
this.wr = wr;
this.login = login;
this.ui = ui;
block.setVisible(false);
wr.b2.addActionListener(new ActionHandler());//waitRoom에서 나가기 버튼
block.b1.addActionListener(new ActionHandler());
wr.b4.addActionListener(new ActionHandler());
}
public void run() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
//서버로부터 수신된 메시지를 모니터로 출력
String str = reader.readLine();
System.out.println("받은문자 : " + str);
if (str.endsWith("!/")) {
continue;
} else {
str = checkFilter(str);
}
StringTokenizer st = new StringTokenizer(str, "##");
String[] result = str.split("##");
if (result[0].equals("50")) {
if (result[1].contains("들어오셨습니다") || result[1].contains("나가셨습니다")) {
if (wr.model2.getRowCount() > 0) {
for (int i = wr.model2.getRowCount() - 1; i > -1; i--) {
wr.model2.removeRow(i);
}
wr.ta.append(result[1] + "\n");
}
} else {
if (!banName.contains(result[1].substring(0, result[1].indexOf(">")))) {
wr.ta.append(result[1] + "\n");
}
}
} else if (result[0].equals("100")) {
System.out.println("클라이언트 정보 : " + result[1]);
System.out.println("클라이언트 정보 : " + result[2]);
String[] row = new String[2];
row[0] = result[1];
row[1] = result[2];
wr.model2.addRow(row);
} else if (str.equals("true")) {
JOptionPane.showMessageDialog(null, "중복된 아이디입니다.\n아이디를 다시 입력해주세요.");
} else if (str.equals("false")) {
wr.setVisible(true);
login.setVisible(false);
} else if (result[0].equals("whisp")) {
System.out.println("ReceiverThreadwHISP : " + Arrays.toString(result));
wr.ta.append("========================================\n");
wr.ta.append(result[1] + "님의 귓속말 ==>> " + result[2] + "\n");
wr.ta.append("========================================\n");
}
if (str == null)
break;
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
class ActionHandler implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == wr.b2) {
block.setVisible(true);
} else if (e.getSource() == block.b1) {
banName.clear();
String result = block.ta.getText();
String[] rs = result.split("\n");
banName = new ArrayList<>(Arrays.asList(rs));
System.out.println("banName 리스트 : " + banName);
block.setVisible(false);
} else if (e.getSource() == wr.b4) {
ui.disp();
ui.setVisible(true);
}
}
}
public static void addFilter(String str) {
if (!filter.contains(str)) {
filter.add(str);
System.out.println(filter + "추가되었습니다.");
} else
System.out.println("이미 추가된 단어입니다.");
}
public String checkFilter(String str) {
for (String s : filter) {
if (str.contains(s))
str = str.replace(s, "**");
}
return str;
}
}
Server.java
package Multicast;
import java.net.ServerSocket;
import java.net.Socket;
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());
}
}
}
PerClientThread.java
// 각 클라이언트 접속에 대해 하나씩 작동하는 스레드 클래스
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<Clients> clientsList = new ArrayList<Clients>();
static int Expulsion, EpCOunt;//강퇴 찬성 횟수, 강퇴 찬반대 신청 횟수
Socket socket;
PrintWriter writer;
Clients client;
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 result = null, id = null, name = null, sex = null;
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
// 수신된 첫번째 문자열을 대화명으로 사용하기 위해 저장
result = reader.readLine();
StringTokenizer st = new StringTokenizer(result, "##");
name = st.nextToken();
sex = st.nextToken();
String flag = Validation(name);
if (flag.equals("true")) {
Exception ex = new Exception("고의로 발생시켰음");
throw ex;
}
client = new Clients(name, sex, writer);
clientsList.add(client);
sendAll("50",
"!" + name + "님이 들어오셨습니다");
sendConnectList();
while (true) {
String str = reader.readLine();
String[] rs = str.split("##");
System.out.println("서버에서 받은 msg : " + str);
if (rs[0] == null) {
break;
} else if (rs[0].equals("exit")) {//클라이언트가 나가기 버튼을 누른 경우
break;
} else if (rs[0].equals("exP")) {//클라이언트가 추방건의를 누른 경우
sendAll("Election", "Election");//모든 클라이언트들에게 메세지 전송
} else if (rs[0].equals("Whispering")) {//클라이언트가 추방건의를 누른 경우
System.out.println("서버에서 귓속말 내용 : " + rs[0] + " " + rs[1] + " " + rs[2] + " ");
sendWhispering(rs[1], rs[2]);//모든 클라이언트들에게 메세지 전송
continue;
}
sendAll("50", name + ">" + str); // 수신된 메시지 앞에 대화명을 붙여서 모든 클라이언트로 송신
}
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
list.remove(writer);
sendAll("50", "!" + name + "님이 나가셨습니다"); // 사용자가 채팅을 종료했다는 메시지를 모든 클라이언트로 보냅니다.
clientsList.remove(client);
sendConnectList();
try {
socket.close();
} catch (Exception ignored) {
}
}
}
// 서버에 연결되어 있는 모든 클라이언트로 똑같은 메시지를 보냅니다.
private void sendAll(String StateCode, String str) {
for (PrintWriter writer : list) {//현재 접송중인 모든 유저에게 msg 전송
writer.println(StateCode + "##" + str);
writer.flush();
}
}
private void sendConnectList() {
for (Clients clist : clientsList) {//현재 접송중인 모든 유저에게 msg 전송
String StateCode = "100";
String str = clist.getName() + "##" + clist.getSex();
System.out.println(str);
sendAll(StateCode, str);
}
}
private void sendWhispering(String name, String msg) {
System.out.println("sendWhisperingMethod : " + name + " : " + msg);
int cnt = 0;
for (Clients xx : clientsList) {
if (xx.getName().equals(name)) {
cnt++;
xx.getWriter().println("whisp##"+this.client.getName()+"##"+msg);
xx.getWriter().flush();
}
}
System.out.println("반복횟수 : " + cnt);
}
private String Validation(String name) {
String flag = "false";
for (Clients xx : clientsList) {
if (xx.getName().equals(name)) {
flag = "true";
}
// else{
// writer.println("12");
// writer.flush();
// }
}
System.out.println(flag);
writer.println(flag);
writer.flush();
return flag;
}
}
UI.Class
Login.java
package Multicast;
import javax.swing.*;
import java.awt.*;
public class Login extends JPanel{
private Image back;
private JLabel la1,la2,la3;
JTextField tf; //default로 잡힌 이유는 다른 클래스에서 사용해야 하기 때문에
JTextField pf; //default로 잡힌 이유는 다른 클래스에서 사용해야 하기 때문에
JButton b1,b2; //default로 잡힌 이유는 다른 클래스에서 사용해야 하기 때문에
JRadioButton rb1, rb2;
public Login()
{
//이미지 정보 읽기
back=Toolkit.getDefaultToolkit().getImage("C:\\Users\\smreo\\Pictures\\Saved Pictures\\back.jpg");
setLayout(null); //직접 배치
// //로그인 부분 아이디와 아이디 칠 textField
// la1=new JLabel("아이디",JLabel.RIGHT);
// la1.setBounds(745, 730, 80, 30);
// tf=new JTextField();
// tf.setBounds(830, 730, 150, 30);
// add(la1); add(tf);
//로그인 부분 비밀번호와 비밀번호 칠 textField
la2=new JLabel("대화명",JLabel.RIGHT);
la2.setBounds(745, 765, 80, 30);
pf=new JTextField();
pf.setBounds(830, 765, 150, 30);
add(la2); add(pf);
rb1=new JRadioButton("남자");
rb2=new JRadioButton("여자");
ButtonGroup bg=new ButtonGroup();
bg.add(rb1); bg.add(rb2);
rb1.setSelected(true);
la3=new JLabel("성별",JLabel.RIGHT);
la3.setBounds(745, 800, 80, 30);
rb1.setBounds(830, 800, 70, 30);
rb2.setBounds(910, 800, 70, 30);
rb1.setOpaque(false);
rb2.setOpaque(false);
add(la3); add(rb1); add(rb2);
b1 = new JButton("로그인");
b2 = new JButton("취 소");
JPanel p = new JPanel(); //패널을 배치하는 이유, 가운데 맞추기 어려워서 패널로 잡아준다
p.add(b1);
p.add(b2);
p.setOpaque(false); // setOpaque -투명모드
p.setBounds(740, 850, 235, 35);
add(p);
}
@Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
g.drawImage(back, 0, 0, getWidth(), getHeight(), this);
}
public static void main(String[] args) {
}
}
WaitRoom.java
package Multicast;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class WaitRoom extends JPanel {
JTable table1, table2;
DefaultTableModel model1, model2;
JTextField tf;
JTextArea ta;
JButton b1, b2, b3, b4, b5, b6;
JScrollBar bar;
public WaitRoom() {
// String[] col1 = {"방이름", "공개/비공개", "인원"};
// String[][] row1 = new String[0][3];
//
// model1 = new DefaultTableModel(row1, col1);
// table1 = new JTable(model1);
// JScrollPane js1 = new JScrollPane(table1);
String[] col2 = {"대화명", "성별"};
String[][] row2 = new String[0][2];
model2 = new DefaultTableModel(row2, col2);
table2 = new JTable(model2);
JScrollPane js2 = new JScrollPane(table2);
ta = new JTextArea();
ta.setEditable(false);
JScrollPane js3 = new JScrollPane(ta);
bar = js3.getVerticalScrollBar();
tf = new JTextField();
b1 = new JButton("추방건의");
b2 = new JButton("차단하기");
b3 = new JButton("채팅방 설정");
b4 = new JButton("단어 필터링");
b5 = new JButton("귓속말 보내기");
b6 = new JButton("나가기");
// 배치
setLayout(null);
// js1.setBounds(10, 15, 600, 500);
// js2.setBounds(10, 520, 600, 350);
js2.setBounds(10, 15, 600, 500);
// add(js1);
add(js2);
js3.setBounds(615, 15, 390, 465);
add(js3);
tf.setBounds(615, 480, 390, 30);
add(tf);
JPanel p = new JPanel();
p.setLayout(new GridLayout(3, 2, 5, 5));
p.add(b1);
p.add(b2);
p.add(b3);
p.add(b4);
p.add(b5);
p.add(b6);
p.setBounds(615, 523, 390, 350);
add(p);
ButtonAction();
}
public void ButtonAction() {
b6.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new Login();
setVisible(false);//창 안보이게 하기
}
});
b3.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new Change();
}
});
//귓속말말
}
class Change extends Frame {
JCheckBox cb1, cb2, cb3, cb4, cb5, cb6;
JButton bb1, bb2;
public Change() {
JPanel p = new JPanel();
p.setLayout(null);
this.add(p);
setSize(400, 400);
setVisible(true);
cb1 = new JCheckBox("Dark");
cb2 = new JCheckBox("Orange");
cb3 = new JCheckBox("Red");
cb4 = new JCheckBox("Green");
cb5 = new JCheckBox("Yellow");
cb6 = new JCheckBox("Bold");
bb1 = new JButton("확인");
bb2 = new JButton("취소");
bb1.setBounds(90, 300, 70, 30);
bb2.setBounds(240, 300, 70, 30);
cb1.setBounds(70, 40, 90, 30);
cb2.setBounds(180, 40, 90, 30);
cb3.setBounds(280, 40, 90, 30);
cb4.setBounds(70, 80, 90, 30);
cb5.setBounds(180, 80, 90, 30);
cb6.setBounds(120, 200, 70, 30);
p.add(bb1);
p.add(bb2);
p.add(cb1);
p.add(cb2);
p.add(cb3);
p.add(cb4);
p.add(cb5);
p.add(cb6);
bb1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
if (cb1.isSelected()) {
ta.setBackground(Color.BLACK);
ta.setForeground(Color.PINK);
} else if (cb2.isSelected()) {
Font font = new Font("digital-7", Font.BOLD, 30);
ta.setBackground(Color.ORANGE);
ta.setForeground(Color.BLACK);
} else if (cb3.isSelected()) {
ta.setBackground(Color.RED);
ta.setForeground(Color.WHITE);
} else if (cb4.isSelected()) {
ta.setBackground(Color.GREEN);
ta.setForeground(Color.YELLOW);
} else if (cb5.isSelected()) {
ta.setBackground(Color.YELLOW);
ta.setForeground(Color.BLACK);
} else if (cb6.isSelected()) {
Font font = new Font("Serif", Font.BOLD, 15);
tf.setFont(font);
ta.setFont(font);
}
dispose();
}
});
bb2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
dispose();
}
});
}
}
}
FilterUi.java
package Multicast;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class FilterUi extends Frame implements ActionListener {
Panel p1, p2, p3;
TextField tf;
static TextArea ta;
Button b1, b2;
public FilterUi() {
super("필터링");
p1 = new Panel();
p2 = new Panel();
p3 = new Panel();
tf = new TextField(35);
ta = new TextArea(10, 35);
b1 = new Button("Delete");
b2 = new Button("Exit");
p1.add(tf);
p2.add(ta);
p3.add(b1);
p3.add(b2);
add("North", p1);
add("Center", p2);
add("South", p3);
b1.addActionListener(this);
b2.addActionListener(this);
addWindowListener(new WindowAdapter() {
public void WindowClosing(WindowEvent e) {
dispose();
dispose();
}
});
setBounds(300, 200, 300, 300);
}
@Override
public void actionPerformed(ActionEvent e) {
String str = e.getActionCommand();
if (ReceiverThread.filter.contains(str)) {
System.out.println(tf.getText());
tf.requestFocus();
disp();
} else if (str.equals("Delete")) {
ReceiverThread.filter.remove(ReceiverThread.filter.indexOf(tf.getText()));
tf.setText("");
disp();
} else if (str.equals("Exit")) {
dispose();
}
}
public static void disp() {
ta.setText("");
for (int i = 0; i < ReceiverThread.filter.size(); i++) {
ta.append(ReceiverThread.filter.get(i) + "\n");
}
}
public static void main(String[] args) {
FilterUi ui = new FilterUi();
}
}
'개인공부 > Java' 카테고리의 다른 글
[Java]입출력을 위한 BufferedReader, BufferedWriter, StringTokenizer, StringBuilder (0) | 2022.09.22 |
---|---|
Java Scripting API: 자바에서 자바스크립트의 함수를 호출하기 (0) | 2022.09.16 |
쿠키와 세션 (0) | 2022.09.04 |
Unicast 프로그램 (0) | 2022.09.02 |
Java 입출력(I/O), 스트림(Stream), 버퍼(Buffer) 개념 (1) | 2022.09.02 |
Contents
소중한 공감 감사합니다