안녕하세요 이번 글에서는 GUI 멀티 채팅 프로그램 예제에 대해서 알아보도록 하겠습니다.
2개의 java파일로 구성되어 있습니다.
ClientFrame
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ClientFrame extends JFrame{
//자유롭게 사용하려면 여기에 필드로 선언해야 한다
//채팅창 프레임을 구성하는 컴포넌트
//textarea 한줄 이상의 문자 입력 보여주기
private JTextArea textarea;
private JTextField sendMsgTf;
private JScrollPane scrollPane;
//서버와의 통신을 위한 소켓
private Socket socket;
private BufferedWriter bw;
public ClientFrame() {
textarea = new JTextArea();
sendMsgTf = new JTextField();
textarea.setEditable(false);//쓰기를 금지함 edit 할 수 없는 상태
scrollPane = new JScrollPane(textarea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
//As needed 즉 필요에의해서 내용이 많아지면 스크롤 바가 생긴다
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
//가로 스크롤은 안만든다
setSize(500, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setTitle("chatting");
sendMsgTf.addKeyListener(new MsgSendListener());
//텍스트 필드에 키 리스너를 등록
//텍스트 필드를 지켜보고 있다가 특정 상황이 오면
//이벤트 리스너에 정의된 내용 실행
add(scrollPane,BorderLayout.CENTER);//프레임에 붙이기
//add(textarea,BorderLayout.CENTER);//프레임에 붙이기
add(sendMsgTf,BorderLayout.SOUTH);//프레임에 붙이기
}
//소켓 설정을 위한 세터
//이제 프레임도 소켓의 정보를 가지게 되었다
public void setSocket(Socket socket) {
this.socket = socket;
try {
OutputStream out = socket.getOutputStream();
bw = new BufferedWriter(new OutputStreamWriter(out));
} catch (Exception e) {
e.printStackTrace();
}
}
//내부 클래스로 이벤트 리스너 만들기
class MsgSendListener implements KeyListener {
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {//키가 눌렸다가 떼어졌을때
//엔터키가 눌렸다가 떼어지면 텍스트 필드에 있는 내용이 텍스트 에어리어에 나타나게
if (e.getKeyCode()==KeyEvent.VK_ENTER) {//각각의 키들이 가지고 있는 코드 값이 나타난다
//VK_ENTER = 상수 , 엔터 키에 대한 키값을 의미한다
String msg = sendMsgTf.getText();
System.out.println(msg);
textarea.append("[ 나 ]: "+msg+"\n");
sendMsgTf.setText("");
try {
bw.write(msg+"\n");
bw.flush();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}//한문장이 끝났다는 것을 알리기 위해서 bufferedWriter에 "\n"을 붙인다
}
}
}
//내부 클래스로 수신 스레드 작성
class TcpClientReceiveThread implements Runnable {
private Socket socket;
public TcpClientReceiveThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//서버로부터 오는 메세지를 읽어서
//텍스트 에어리어에 추가하기
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
String msg = br.readLine();//메세지 한줄 읽어오기
textarea.append("[상대방]" + msg + "\n");
}
} catch (Exception e) {
textarea.append("연결이 종료되었습니다.");
//System.out.println("연결이 종료되었습니다.");
}
finally {
try {
if (socket!=null&&!socket.isClosed()) {
socket.close();//다 쓴 소켓 닫기
}
} catch (Exception e2) {
}
}
}
}
public static void main(String[] args) {
try {
//서버 아이피 , 포트번호 -> 소켓 생성 -> 연결 요청
Socket socket = new Socket("10.10.10.134", 5000);
//소켓 객체 생성
ClientFrame cf = new ClientFrame();
cf.setSocket(socket);//메인에서 프레임 생성
TcpClientReceiveThread th1 = cf.new TcpClientReceiveThread(socket);
//TcpClientReceiveThread가 내부 클래스로 선언되어 있기 때문에
//cf로 접근해서 socket을 전달한다
new Thread(th1).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
TcpChatServer
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
class TcpChatServerManager {
private List<Socket> socketList;
// 생성자 : TCSM 객체를 생성하면 소켓리스트 하나 만듬
public TcpChatServerManager() {
socketList = new ArrayList<Socket>();
}
// 소켓 추가 메소드
public void addSocket(Socket socket) {
this.socketList.add(socket);
new Thread(new ReceiverThread(socket)).start();
}
// 멀티클라이언트와 연결을 동시에 유지하기 위한 스레드 구성
// 각각의 소켓정보를 가지고 있어야함.
class ReceiverThread implements Runnable {
private Socket socket; // 소켓
public ReceiverThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
// 클라이언트가 보낸 메시지 읽기 위한 작업
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
String msg = br.readLine(); // 클라이언트가 보낸 메시지 읽기
System.out.println(msg);
// 받은 메시지를 메시지 보낸 클라이언트 제외하고
// 모든 클라이언트한테 보내기
Socket tmpSocket = null;
try {
for (int i = 0; i < socketList.size(); i++) { // 소켓리스트를 순회하면서
tmpSocket = socketList.get(i);
// socketList.get(0) -> 소켓 객체
if (socket.equals(tmpSocket)) continue;
// 메시지를 보낸 클라이언트라면 반복을 한번 건너뛰기
// 서버가 받은 메시지를 클라이언트에 송신하기
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(tmpSocket.getOutputStream()));
bw.write(msg + "\n");
bw.flush();
}
}catch(Exception e) {
System.out.println(tmpSocket.getRemoteSocketAddress() + "연결 종료");
socketList.remove(tmpSocket);
//연결을 끊은 클라이언트를 위한 소켓 제거
System.out.println("===============현재참여자=================");
for(Socket s : socketList) {
System.out.println(s.getRemoteSocketAddress());
}
System.out.println("==========================================");
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
finally {
if(socket != null) {
System.out.println(socket.getRemoteSocketAddress() + "연결 종료");
socketList.remove(socket);
//연결을 끊은 클라이언트를 위한 소켓 제거
System.out.println("===============현재참여자=================");
for(Socket s : socketList) {
System.out.println(s.getRemoteSocketAddress());
}
System.out.println("==========================================");
}
}
}
}
}
public class TcpChatServer {
public static void main(String[] args) {
// 서버소켓
TcpChatServerManager tcsm = new TcpChatServerManager();
try {
ServerSocket serverSocket = new ServerSocket(5000);
while (true) {
Socket socket = serverSocket.accept(); // 클라이언트 연결요청 대기(연결요청 오기전엔 멈춤)
// -> 연결요청오면? 소켓을 반환
// 멀티 클라이언트 -> 소켓이 여러개 -> 리스트로 관리
// -> 서버 매니져 클래스로 관리
System.out.println(socket.getRemoteSocketAddress() + " : 연결");
tcsm.addSocket(socket); // 얻은 소켓 서버매니져의 소켓목록에 추가
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
실행 화면
'Java 프로그래밍 예제' 카테고리의 다른 글
자바 TCP 채팅 코드 (2) | 2017.11.05 |
---|---|
자바 GUI 환율 계산기 예제 (0) | 2017.11.01 |
2차원 배열에 숫자를 차례대로 출력하기 (5) | 2017.09.29 |
자바 전기 요금 계산 예제 (0) | 2017.09.28 |
1+(1+2)+(1+2+3)+(1+2+3+4)+(1+2+3+4+5)... 의 합을 구하는 프로그램 (0) | 2017.09.26 |
댓글