영보의 SystemOut.log

[JAVA]자바 라이브러리로 채팅 프로그램 만들기 본문

Language/JAVA

[JAVA]자바 라이브러리로 채팅 프로그램 만들기

영보로그 2020. 7. 31. 15:30
반응형

안녕하세요

자바 라이브러리를 이용하여 간단하게 채팅할 수 있는 프로그램을 만들어 봤습니다.

아직 미완성이지만, 도움이 됐으면 하고 포스팅을 시작하겠습니다.

 

 

저는 3개의 패키지와 그 안에 각각 클래스를 만들어서

연동하였으니 참고 바랍니다!

 

 

 


Function.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.sist.common;
 
// Client,Server=>공통으로 사용하는 클래스
// 프로그램의 기능 설정=>내부 프로토콜(서버와 클라이언트의 약속)
// 웹서버
public class Function {
    // 로그인 처리
    public static final int LOGIN = 100;
    public static final int MYLOG = 110;
 
    // 대기실 채팅
    public static final int WAITCHAT=500;
    // 방 채팅
}
cs

 

Server.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package com.sist.server;
 
import java.util.*;
import com.sist.common.Function;
import java.io.*;//입출력 (서버와 클라이언트 통신)
import java.net.*//다른 컴퓨터와 연결
 
public class Server implements Runnable {
    private ServerSocket ss;
    private final int PORT = 1120;
    private Vector<Client> waitVc = new Vector<Client>();
    // 쓰레드에서 동기화 프로그램
 
    // 서버 가동
    public Server() {
        try {
            ss = new ServerSocket(PORT);
            /*
             * bind() => IP, PORT 묶어주는 역할 ==> 핸드폰 (개통) listen() => 대기상태(클라이언트가 접속하기 전까지 대기)
             */
            System.out.println("Server Start...");
        } catch (Exception ex) {
        }
    }
 
    // 클라이언트가 접속을 했을 경우 => 각자 통신이 가능하게 쓰레드와 연결
    @Override
    public void run() {
        try {
            while (true) {
                Socket s = ss.accept();
                // accept() : 특수한 메소드 => 클라이언트가 접속시에만 호출되는 메소드
                Client client = new Client(s);
                client.start(); // 클라이언트와 통신 승인
            }
        } catch (Exception ex) {
        }
    }
 
    public static void main(String[] args) {
        //서버가동
        Server server=new Server();
        new Thread(server).start();
        //Server 클래스에 있는 run을 호출
 
    }
 
    // 내부 클래스 => Server가 가지고 있는 데디터 쉽게 공유가 가능하게 만든다
    class Client extends Thread {
        // 클라이언트와 연결
        Socket s;
        // 클라이언트로부터 요청을 받는다
        BufferedReader in;
        // 요청을 처리한 다음에 결과를 응답
        OutputStream out;
        String id, name, sex, pos;
 
        public Client(Socket s) {
            try {
                this.s = s;
                in = new BufferedReader(new InputStreamReader(s.getInputStream()));
                // 클라이언트 요청한 메소드를 읽어오는 메모리 공간
                out = s.getOutputStream();
            } catch (Exception ex) {
            }
        }
 
        // 통신 ? => 기능(요청처리)
        public void run() {
            try {
                while (true) {
                    // 클라이언트가 요청한 내용 받는다
                    String msg = in.readLine();
                    StringTokenizer st = new StringTokenizer(msg, "|");
                    int protocol = Integer.parseInt(st.nextToken());
                    // 100|id|대화명|성별
                    switch (protocol) {
                    case Function.LOGIN: {
                        // 로그인처리
                        // 데이터 값 받기
                        id = st.nextToken();
                        name = st.nextToken();
                        sex = st.nextToken();
                        pos = "대기실"// 사용자의 기본정보
 
                        // 접속한 모든 사용자 => 로그인한 정보를 보내준다
                        messageAll(Function.LOGIN + "|" + id + "|" + name + "|" + sex + "|" + pos);
                        // 접속한 사람의 정보를 저장
                        waitVc.add(this);
                        // Client client=new Client();
                        messageTo(Function.MYLOG + "|" + id);
                        // 로그인창에서 => 대기창으로 변경
                        for (Client user : waitVc) {
                            messageTo(
                                    Function.LOGIN + "|" + user.id + "|" + user.name + "|" + user.sex + "|" + user.pos);
                        }
                        // 입장 메세지 출력
                        messageAll(Function.WAITCHAT+"|[☞"+name+"님이 입장하셨습니다.");
                        // 개설된 방정보 전송
                    }
                        break;
                    case Function.WAITCHAT:
                    {
                        messageAll(Function.WAITCHAT+"|["+name+"]"+st.nextToken());
                    }
                    }
                }
            } catch (Exception ex) {
            }
 
        }
 
        // 응답처리
        public synchronized void messageTo(String msg) {
            // synchronized
            /*
             * 쓰레드는 default : 비동기화 synchronized => 동기화
             */
            try {
                out.write((msg + "\n").getBytes()); // 데이터를 1명한테만 보내는 거
                // 인코딩 ==> 디코딩
            } catch (Exception ex) {
            }
        }
 
        // 전체적으로 응답
        public synchronized void messageAll(String msg) {
            try {
                for (Client user : waitVc) {
                    user.messageTo(msg);
                }
            } catch (Exception ex) {
            }
        }
    }
 
}
cs

 - 서버를 담당하는 코드입니다. 여기서 먼저 서버를 연 다음, 메인 폼을 실행해야 접속이 가능합니다.

 - 10번째 줄의 1120은 제 포트번호 입니다. 네트워크 상에서 겹치지않는 원하시는 포트번호로 하시면 됩니다!

 

 

Login.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.sist.client;
 
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:\\javaDev\\back.png");
      setLayout(null); //직접 배치
      
      //로그인 부분 아이디와 아이디 칠 textField
      la1=new JLabel("아이디",JLabel.RIGHT);
      la1.setBounds(7457308030);
      tf=new JTextField();
      tf.setBounds(83073015030);
      add(la1); add(tf);
      
      //로그인 부분 비밀번호와 비밀번호 칠 textField
      la2=new JLabel("대화명",JLabel.RIGHT);
      la2.setBounds(7457658030);
      pf=new JTextField();
      pf.setBounds(83076515030);
      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(7458008030);
      rb1.setBounds(8308007030);
      rb2.setBounds(9108007030);
      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(74085023535);
      add(p);
      }
      
   @Override
   protected void paintComponent(Graphics g) {
      // TODO Auto-generated method stub
      g.drawImage(back, 00, getWidth(), getHeight(), this);
   }
   
   public static void main(String[] args) {
   
   }
}
cs

 - 메인 폼을 실행하기 위해  필요한 페이지입니다. 

 

 

ClientMainForm.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package com.sist.client;
 
import java.util.*;
import javax.swing.*;
import com.sist.common.Function;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
 
public class ClientMainForm extends JFrame implements ActionListener, Runnable {
    CardLayout card = new CardLayout();
    Login login = new Login();
    WaitRoom wr = new WaitRoom();
    // 네트워크
    Socket s; // 전화기
    BufferedReader in// 수신
    OutputStream out// 송신
 
    public ClientMainForm() {
        setLayout(card);
        add("LOGIN", login);
        add("WR", wr);
        setSize(1024950);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
 
        login.b1.addActionListener(this);
        login.b2.addActionListener(this);
        
        wr.tf.addActionListener(this);
    }
 
    public static void main(String[] args) {
        new ClientMainForm();
    }
 
    public void connection(String id, String name, String sex) {
        // 서버연결 => 로그인 요청
        try {
            s = new Socket("localhost",1120); // localhost=> 본인꺼 , 남들꺼는 남들 IP주소 써야함
            in = new BufferedReader(new InputStreamReader(s.getInputStream()));
            out = s.getOutputStream();
            // 연결이 되면 로그인 요청
            out.write((Function.LOGIN + "|" + id + "|" + name + "|" + sex + "\n").getBytes());
        } catch (Exception ex) {
        }
        // 연결이 되면 지시를 받는다
        new Thread(this).start();
    }
 
    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        if(e.getSource()==login.b1) {
            String id=login.tf.getText();
            String name=login.pf.getText();
            String sex="";
            if(login.rb1.isSelected())
                sex="남자";
            else
                sex="여자";
            connection(id, name, sex);
        }
        else if(e.getSource()==wr.tf)
        {
            // 입력된 데이터 읽기
            String msg=wr.tf.getText();
            if(msg.length()<1return;
            
            try {
                out.write((Function.WAITCHAT+"|"+msg+"\n").getBytes());
            }catch(Exception ex) {}
            
            wr.tf.setText("");
        }
 
    }
 
    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            while (true) {
                String msg = in.readLine();
                StringTokenizer st = new StringTokenizer(msg, "|");
                int protocol = Integer.parseInt(st.nextToken());
                switch (protocol) {
                case Function.LOGIN: {
                    String[] data= {
                            st.nextToken(),
                            st.nextToken(),
                            st.nextToken(),
                            st.nextToken()
                    };
                    wr.model2.addRow(data);
                }
                    break;
                case Function.MYLOG: {
                    setTitle(st.nextToken());
                    card.show(getContentPane(), "WR");
                }
                break;
                case Function.WAITCHAT:{
                    wr.bar.setValue(wr.bar.getMaximum());
                    wr.ta.append(st.nextToken()+"\n");
                }
                }
 
            }
        } catch (Exception ex) {
        }
 
    }
}
 
cs

 - 41번째 줄 보시면, 본인 IP들어갈 때는 [localhost]를 입력하고 임의의 포트번호를 입력하시면 되지만, 

다른 User의 IP를 공유하여 함께 사용 시, [시작] - [검색] - [cmd] 의 명령 프롬프트 창에서 리눅스 명령어 [ipconfig] 를 입력해서 나오는 IP주소를 공유하여 들어가면 됩니다.

 

 

 

WaitRoom.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.sist.client;
 
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
 
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 = { "ID""대화명""성별""위치" };
        String[][] row2 = new String[0][3];
 
        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(1015600500);
        js2.setBounds(10520600350);
        add(js1);
        add(js2);
 
        js3.setBounds(61515390465);
        add(js3);
 
        tf.setBounds(61548039030);
        add(tf);
 
        JPanel p = new JPanel();
        p.setLayout(new GridLayout(3255));
        p.add(b1);
        p.add(b2);
        p.add(b3);
        p.add(b4);
        p.add(b5);
        p.add(b6);
 
        p.setBounds(615523390350);
        add(p);
    }
}
cs

 - 화면 UI를 표시하는 코드입니다. (자세한건 코드 보시는게 나으실듯)

 

 

 

먼저 Server.java를 실행해서 서버를 킵니다.

 

 

 

로그인 폼에서 로그인을 해 줍니다.

 

 

들어왔다고 저장이 되고, 채팅창에서 채팅이 됩니다.

 

게임과 기능들은 추가하겠습니다.

반응형