자바 채팅 프로그램을 만들려고 여러 시행착오를 거쳐왔는데
이제 완성이 되었네요 ㅠㅠ.
여러 웹서핑으로 만들어진 채팅 프로그램입니다!!!

package com.aaa.client;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.PrintWriter;
import javax.swing.JButton;
import javax.swing.JPanel;
public class Clientgui extends Frame implements ActionListener{
private TextArea chatviewer; //채팅 대화창 만들기
private TextField tfname; //이름 입력칸 만들기
private TextField tfport; //포트번호 입력칸 만들기
private TextField tfip; //ip 입력칸 만들기
private JButton login; //로그인버튼으로 서버와 연결한다.
private TextField tfinput; //대화입력칸 만들기
private JButton tfenter; //엔터 버튼을 올려 대화내용을 공유한다.
private PrintWriter pw; //데이터를 서버로 보내는 스트림이다.
private String idname; //tfname에서 아이디를 가져올때 사용한다.
private String serverip; //tfip에서 ip를 가져올때 사용한다.
private int portnum = 10000;//지정된 포트번호
public Clientgui() {
//패널선언
JPanel up = new JPanel();
JPanel center = new JPanel();
JPanel down = new JPanel();
//up
tfname = new TextField("이름",5);// 이름입력칸구성하기
tfname.setText("이름 입력");
tfname.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
tfname.setText("");
}
});
tfport = new TextField(Integer.toString(portnum),5);// 포트번호 입력칸 구성하기
tfport.setText("10000");
tfip = new TextField("127.0.0.1",5);//ip입력칸 구성하기.
tfip.setText("127.0.0.1");
login = new JButton("시작"); //로그인 버튼 구성하기
login.setPreferredSize(new Dimension(67,23));
login.addActionListener(this);
//center
chatviewer = new TextArea(""); //채팅창 구성하기
chatviewer.setPreferredSize(new Dimension(278,285));
chatviewer.setEnabled(false);
//down
tfinput = new TextField(""); //입력창 구성하기
tfinput.setPreferredSize(new Dimension(210,25));
tfinput.addActionListener(this);
tfenter = new JButton("엔터");//엔터 버튼 구성하기
tfenter.setPreferredSize(new Dimension(60,25));
tfenter.addActionListener(this);
// 해당되는 패널에 각 요소들을 넣어준다.
up.add(tfname);
up.add(tfport);
up.add(tfip);
up.add(login);
center.add(chatviewer);
down.add(tfinput);
down.add(tfenter);
//Borderlayout을 이용해 위치를 지정한다.
add(up,BorderLayout.NORTH);
add(center,BorderLayout.CENTER);
add(down, BorderLayout.SOUTH);
//프레임 크기 설정
setSize(300,400);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
//Event 객체를 반환한다.
Object obj = e.getSource();
if (obj == login) {
// 로그인 버튼을 누르면 init()의 실행을 통해 Event가 서버와 연결한다.
idname = tfname.getText();
serverip = tfip.getText();
portnum = Integer.parseInt(tfport.getText());
init();
chatviewer.setText("채팅 시작\n");
login.setEnabled(false);
} else if (obj == tfinput || obj == tfenter) {
// Event가 textfield의 문장을 엔터버튼이나
//키보드의 엔터키를 통해 받으면 서버와 연결된다.
String msg = tfinput.getText();
//채팅내용을 다음 코드문에 따라 가공해서 전송한다.
if (!msg.trim().equals("")) {
try {
String str = "contents"+":"+ idname + ":" + msg;
pw.println(str);
pw.flush();
tfinput.setText("");
tfinput.setFocusable(true);
} catch (Exception e2) {
e2.printStackTrace();
}
} else {
System.out.println("Error");
}
}
}
//Clientgui의 네트워크를 구현한다.
public void init() {
ClientNetwork clientNetwork = new ClientNetwork(this,serverip,portnum);
//클라이언트 네트워크 클래스 선언
Thread thread = new Thread(clientNetwork);
thread.start();
try {
//Thread 실행후 Socket에 대한 출력 스트림 객체를 반환하여 멤버변수에 저장한다.
//다음 출력스트림은 서버로 채팅메시지 전송에 사용된다.
pw = clientNetwork.getPw();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Clientgui clientgui = new Clientgui();
clientgui.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
//채팅창을 나가면 다음 메시지가 나간다.
String str = "end"+":"+clientgui.getIdname();
clientgui.getPw().println(str);
clientgui.getPw().flush();
System.exit(0);
}
});
}
public PrintWriter getPw() {
return pw;
}
public TextArea getChatviewer() {
return chatviewer;
}
public String getIdname() {
return idname;
}
//ClientNetwork 클래스에서 쓰일 메소드이다.
// 채팅창에 메시지 전달을 담당한다.
public void appendMsg(String msg) {
chatviewer.append(msg);
}
}
1. Clientgui(클라이언트 gui프로그램)
package com.aaa.client;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
public class ClientNetwork extends Thread {
//채팅 clientgui 객체이다.
private Clientgui clientgui;
//서버와 연결된 socket을 담당한다.
private Socket socket;
private BufferedReader br;
private PrintWriter pw;
private String id;
//serversocket과 연결된 socket을 멤버변수에 저장하고 출력스트림 객체를 생성한다.
public ClientNetwork(Clientgui clientgui, String ip, int port){
this.clientgui=clientgui;
id=clientgui.getIdname();
try {
socket = new Socket(ip,port);
pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
} catch (Exception e) {
e.printStackTrace();
}
}
//Thread 실행을 위한 run함수 이다.
@Override
public void run() {
String message = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//서버에 접속한 후 채팅입장여부를 확인하는 문장을 전송한다.
message = "id"+":"+id;
pw.println(message);
pw.flush();
//무한루프를 돌며 서버로부터 수신되는 메시지를 표시한다.
//만약 socket와의 연결이 끊어지면 thread가 정지된다.
while (true) {
message=br.readLine();
clientgui.getChatviewer().append(message+"\n");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public PrintWriter getPw() {
return pw;
}
public void setPw(PrintWriter pw) {
this.pw = pw;
}
}
2. ClientNetwork(Clientgui 네트워크 프로그램)
package com.aaa.server;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Servergui extends JFrame implements ActionListener{
//채팅창을 선언한다.
private TextArea chats;
//String은 id가 들어가고 printwriter는 출력 스트림 객체를 저장한다.
private Map<String, PrintWriter> clientMap;
// 포트번호 선언
private int portnum = 10000;
//생성자를 선언한다.
public Servergui() {
JPanel panel = new JPanel();
FlowLayout flowLayout = new FlowLayout();
//채팅상환을 표시하는 textarea이다.
chats = new TextArea();
chats.setPreferredSize(new Dimension(450,450));
chats.setEditable(false);
panel.setLayout(flowLayout);
panel.add(chats);
add(panel,BorderLayout.CENTER);
setSize(500,500);
setVisible(true);
}
// 동작하는 동안 포트번호를 받아들이고 접속했다는 메시지를 출력한다.
public void init() {
ServerSocket serverSocket = null;
try {
//연결된 클라이언트를 저장할 Map<client_id, output_stream>를 생성한다. 생성 후 동기화를 설정한다.
serverSocket = new ServerSocket(portnum);
clientMap = new HashMap<String, PrintWriter>();
Collections.synchronizedMap(clientMap);
//serversocket에 연결이 이루어지면 해당 socket를 반환하고
//채팅서버를 담당하는 ServerNetwork객체의 생성자에 매개변수를 넘겨 객체를 생성한다.
while (true) {
chats.append("연결중\n");
Socket socket = serverSocket.accept();
ServerNetwork serverNetwork = new ServerNetwork(clientMap, this, socket);
Thread thread = new Thread(serverNetwork);
thread.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Servergui servergui = new Servergui();
servergui.init();
}
@Override
public void actionPerformed(ActionEvent e) {}
public void appendMsg(String msg) {
chats.append(msg);
}
public TextArea getChats() {
return chats;
}
public void setChats(TextArea chats) {
this.chats = chats;
}
}
3. Servergui(서버 gui 프로그램)
package com.aaa.server;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
public class ServerNetwork extends Thread{
//포트번호가 들러올 수 있는 소켓과
//데이터가 다녀갈 수 있는 input과 output, Severgui클래스를 선언한다.
//채팅서버의 gui를 담당하는 Servergui 객체와
//채팅클라이언트를 저장하는 Map<클라이언트ID, 출력스트림객체> 객체를 지정한다.
private Map<String, PrintWriter> clientMap;
private Servergui servergui;
private Socket socket;
private BufferedReader br;
private String id;
private boolean condition=true;
public ServerNetwork(Map<String, PrintWriter>clientMap, Servergui servergui, Socket socket) {
this.clientMap=clientMap;
this.servergui=servergui;
this.socket=socket;
}
//Thread 실행을 위한 run함수
@Override
public void run() {
String message = null;
String receivedMsg[] = null;
try {
//ServerSocket에서 반환되어 온 Socket 객체에서 입출력 스트림 객체를 불러온다.
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
//receivedMsg[0] receivedMsg[1] receivedMsg[2]
//id <채팅 아이디> //채팅방에서 입장할 때 전달된다.
//contents <채팅 아이디> <채팅 내용> //채팅방에서 진행되는 채팅내용이 전달된다.
//end <채팅 아이디> //채팅방에서 탈퇴시 전달된다.
while (condition) {
message = br.readLine();
receivedMsg = message.split(":");
if (receivedMsg[0].equals("id")) {
//채팅 클라이언트를 저장하는 Map 객체에 id와 출력 스티림 객체를 저장한다.
clientMap.put(receivedMsg[1], pw);
//servergui로 출력한다.
servergui.getChats().append(receivedMsg[1]+" 님이 연결되었습니다.\n");
//다른 클라이언트로 메시지를 발송한다.
broadcast(receivedMsg[1] + " 님이 연결되었습니다.");
} else if (receivedMsg[0].equals("contents")) {
//servergui로 출력한다.
servergui.getChats().append("["+receivedMsg[1]+"]"+": "+receivedMsg[2]+"\n");
//다른 클라이언트로 메시지를 발송한다.
broadcast("["+receivedMsg[1]+"]"+": "+receivedMsg[2]);
} else if(receivedMsg[0].equals("end")){
//채팅 클라이언트를 저장하는 Map 객체에 id와 출력 스티림 객체를 삭제한다.
clientMap.remove(receivedMsg[1]);
//servergui로 출력한다.
servergui.getChats().append(receivedMsg[1]+" 님이 퇴장하셨습니다."+"\n");
//다른 클라이언트로 메시지를 발송한다.
broadcast(receivedMsg[1]+" 님이 퇴장하셨습니다."+"\n");
//조건을 false로 바꾸어 while을 종료한다.
condition = false;
} else {
System.out.println("ServerNetwork: Error");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
//보유하고 있는 모든 Map객체로 메시지를 발송한다.
private void broadcast(String msg) {
Collection<PrintWriter> collection = clientMap.values();
Iterator<PrintWriter> iterator = collection.iterator();
while (iterator.hasNext()) {
PrintWriter pw = iterator.next();
System.out.println(msg);
pw.println(msg);
pw.flush();
}
}
}
4. ServerNetwork(서버 gui 네트워크 프로그램)
현재 방학 중이네요...
빨리 코로나가 끝나서 대면으로 동기들도 만나고 싶네요
이번 여름 잘 지내세요!

'Java > Chat' 카테고리의 다른 글
[자바] 콘솔창을 이용한 자바채팅프로그램 (0) | 2021.07.02 |
---|---|
[자바] 에코서버 만들기 (0) | 2021.07.02 |