MyChatServer 프로젝트
ChatServer.java
import java.io.BufferedWriter;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class ChatServer {
// 스레드간의 정보를 공유할 HashMap
// key는 채팅별명(아이디)이고 value는 출력스트림
Map<String, BufferedWriter> map;
public ChatServer() {
map = new HashMap<>();
ServerSocket serverSocket = null; // 서버소켓
Socket socket = null; // 클라이언트와 통신하기 위한 소켓
final int PORT = 6000; // 포트번호
try {
serverSocket = new ServerSocket(PORT);
System.out.println("*** 채팅 서버 ***");
System.out.println("서버는 클라이언트 소켓의 접속요청을 기다리고 있음");
while (true) {
socket = serverSocket.accept();
ChatServerRunnable chatServerRunnable = new ChatServerRunnable(socket, map);
Thread thread = new Thread(chatServerRunnable);
thread.start(); // 스레드 시작
}
} catch (IOException e) {
e.printStackTrace();
System.exit(0);
} finally {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} // ChatServer()
public static void main(String[] args) {
new ChatServer();
} // main()
}
ChatServerRunnable.java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
public class ChatServerRunnable implements Runnable {
Socket socket; // 매번 새로운 클라이언트 정보의 소켓
Map<String, BufferedWriter> map; // 공유데이터
BufferedReader reader = null; // 클라이언트로부터 데이터를 수신받기 위한 스트림
BufferedWriter writer = null; // 클라이언트에게 데이터를 송신하기 위한 스트림
String userId; // 접속자의 아이디(채팅이름)
public ChatServerRunnable(Socket socket, Map<String, BufferedWriter> map) {
this.socket = socket;
this.map = map;
InetAddress inetAddress = socket.getInetAddress();
System.out.println(inetAddress + "로부터 연결요청 받음");
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
// 새로운 클라이언트가 접속해서 처음보낸 문자열은 아이디
userId = reader.readLine();
broadcast(userId + "님이 접속하셨습니다.");
System.out.println("접속한 클라이언트의 아이디는 " + userId + "입니다.");
// 여러 스레드가 공유하는 맵을 동기화함
synchronized (map) {
// 맵은 모든 클라이언트에 의해 공유되어
// 메시지 브로드캐스팅을 위해 출력스트림을 맵에 저장
map.put(userId, writer);
}
} catch (Exception e) {
e.printStackTrace();
}
} // ChatRunnable
@Override
public void run() {
String line = "";
try {
while (true) {
line = (String) reader.readLine();
if (line.equals("/quit")) { // "/quit" 종료
break;
} else { // 받은 메시지를 모든 클라이언트에게 브로드캐스팅함
broadcast(userId + " : " + line);
}
} // while
} catch (Exception e) {
e.printStackTrace();
} finally { // "/quit" 종료 명령어 메시지가 오면
synchronized (map) {
map.remove(userId); // 종료명령어를 보낸 클라이언트의 정보를 맵에서 삭제
}
broadcast(userId + "님이 나가셨습니다."); // 나머지 클라이언트들에게 접속종료 알림
System.out.println(userId + "님이 나가셨습니다."); // 서버에도 출력
try {
if (socket != null) {
socket.close(); // 나간 클라이언트 소켓객체를 닫기
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
} // run()
// 받은 메시지를 모든 클라이언트에게 브로드캐스팅하기 위한 메소드
public void broadcast(String message) {
synchronized (map) {
Collection<BufferedWriter> collection = map.values();
try {
Iterator<BufferedWriter> iter = collection.iterator();
while (iter.hasNext()) {
BufferedWriter writer = iter.next();
writer.write(message + "\n");
writer.flush();
}
// for (BufferedWriter writer : collection) {
// writer.write(message + "\n");
// writer.flush();
// }
} catch (Exception e) {
e.printStackTrace();
}
} // synchronized
} // broadcast()
} // ChatRunnable class
MyChatClient 프로젝트
GUIChatClient.java
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class GUIChatClient extends JFrame implements ActionListener {
static final int SERVER_PORT = 6000; // 포트번호
Socket socket;
BufferedReader reader; // 서버로부터 데이터를 전송받기 위한 스트림
BufferedWriter writer; // 서버에게 데이터를 전송하기 위한 스트림
String userId; // 접속자의 아이디(채팅이름)을 저장할 변수 선언
// 화면구성
CardLayout cardLayout;
JTextField tfServerIp; // 접속할 서버IP를 입력받을 텍스트필드
JTextField tfName; // 접속 대화명을 입력받을 텍스트필드
JButton btnConnect; // 서버 접속 버튼
JTextArea textArea; // 채팅내용 출력 용도
JScrollPane scrollPane;
JTextField tfInput; // 채팅내용 입력할 텍스트필드
JButton btnSend; // 채팅내용(문자열) 전송 버튼
JButton btnExit; // 프로그램 종료 버튼
Container contentPane;
public GUIChatClient() {
setTitle("채팅 클라이언트");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = getContentPane();
cardLayout = new CardLayout();
contentPane.setLayout(cardLayout);
// 접속화면
JPanel connectPanel = new JPanel();
connectPanel.setLayout(new BorderLayout());
connectPanel.add(new JLabel("다중 채팅 접속화면", JLabel.CENTER), BorderLayout.NORTH);
// 접속창 하위패널
JPanel subConnectPanel = new JPanel();
subConnectPanel.add(new JLabel("서버 아이피: "));
tfServerIp = new JTextField("127.0.0.1", 15);
subConnectPanel.add(tfServerIp);
subConnectPanel.add(new JLabel(" 대화명: "));
tfName = new JTextField("아이언맨", 15);
subConnectPanel.add(tfName);
connectPanel.add(subConnectPanel, BorderLayout.CENTER);
btnConnect = new JButton("서버 접속");
connectPanel.add(btnConnect, BorderLayout.SOUTH);
btnConnect.addActionListener(this);
// 채팅화면
JPanel chatPanel = new JPanel();
chatPanel.setLayout(new BorderLayout());
chatPanel.add(new JLabel("채팅 프로그램", JLabel.CENTER), BorderLayout.NORTH);
textArea = new JTextArea(10, 35); // 채팅내용 출력창 용도
scrollPane = new JScrollPane(textArea);
chatPanel.add(scrollPane, BorderLayout.CENTER);
JPanel subChatPanel = new JPanel(); // 채팅창 하위패널
tfInput = new JTextField("", 13);
btnSend = new JButton("전송");
btnExit = new JButton("종료");
tfInput.addActionListener(this);
btnSend.addActionListener(this);
btnExit.addActionListener(this);
subChatPanel.add(tfInput);
subChatPanel.add(btnSend);
subChatPanel.add(btnExit);
chatPanel.add(subChatPanel, BorderLayout.SOUTH);
contentPane.add("접속창", connectPanel);
contentPane.add("채팅창", chatPanel);
cardLayout.show(contentPane, "접속창");
setLocationByPlatform(true);
setSize(300, 300);
setVisible(true);
} // GUIChatClient()
//
public void init() throws IOException {
String ipAddr = tfServerIp.getText();
socket = new Socket(ipAddr, SERVER_PORT);
System.out.println("ipAddr : " + ipAddr);
if (socket != null) {
System.out.println("socket not null");
}
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
if (reader != null) {
System.out.println("reader not null");
}
if (writer != null) {
System.out.println("writer not null");
}
userId = tfName.getText(); // 대화명 가져와서
writer.write(userId + "\n"); // 서버에게 전송
writer.flush();
System.out.println("userId : " + userId);
// 서버가 보낸 데이터를 수신받기 위한 스레드 준비 후 시작
Thread thread = new Thread(new ReadRunnable());
thread.start();
cardLayout.show(contentPane, "채팅창"); // 채팅창으로 화면전환
tfInput.requestFocus(); // 포커스 주기
} // init()
// 서버가 보낸 데이터를 수신받기 위한 내부클래스
class ReadRunnable implements Runnable {
@Override
public void run() {
String line = ""; // 서버로부터 받은 데이터를 저장하기 위한 변수
try {
while (true) {
line = reader.readLine(); // 서버 데이터 수신
textArea.append(line + "\n");
textArea.setCaretPosition(textArea.getText().length());
}
} catch (Exception e) {
e.printStackTrace();
}
} // run()
} // class ReadRunnable
@Override
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();
try {
if (obj == btnConnect) { // 채팅서버 접속버튼
init();
} else if (obj == tfInput || obj == btnSend) { // 텍스트필드에서 엔터키를 쳤거나 전송버튼 눌렸을때
String sendMsg = tfInput.getText();
writer.write(sendMsg + "\n");
writer.flush();
tfInput.setText("");
tfInput.requestFocus();
} else if (obj == btnExit) { // 종료버튼
System.exit(0); // 프로그램 강제 종료
}
} catch (Exception e2) {
e2.printStackTrace();
textArea.append(e2.getMessage() + "\n");
}
} // actionPerformed()
public static void main(String[] args) {
new GUIChatClient();
}
}
'IT > Java' 카테고리의 다른 글
Java - 오버로딩, 오버라이딩, 인터페이스 (0) | 2018.11.24 |
---|---|
응용SW기초기술활용(윈도우 명령 프롬프트(DOS)용 명령어, 리눅스(유닉스) 콘솔 명령어) (0) | 2018.11.23 |
java - JFrame으로 구성한 쓰레드 원리 확인 프로그래스바 (Thread, JProgressBar) (0) | 2018.11.23 |
java - Thread 적용전 채팅 소스 (0) | 2018.11.22 |
java - Http 통신, URLConnection (0) | 2018.11.22 |