티스토리 뷰
Java Chat 자바 채팅프로그램 스윙, 소켓, 스레드, 파일입출력 사용 chatting program using swing gui, socket, thread and fileIO.
j0n9m1n1 2017. 11. 15. 11:28기본 사용법은 ChatNowServer먼저 실행시키시고 start클릭하셔서 시작시키시고
ChatNowClient 실행시키시고 Connect -> Req Server 클릭하셔서 서버와 연결후
Account -> Login에 ID, PW을 치시고 쓰시면 되는데
ID, PW은 FileIO를 사용하였고 소스에 잡혀있는 경로가 D:\login.txt 이고
login.txt파일의 형식은 StringTokenizer를 이용해 " "를 구분자로 주었기 때문에
root root
admin admin
j0n9m1n1 2014244057
ID 공백 PW 이런식으로 되어있습니다.
실행화면은 이렇습니다.
클라이언트와 서버 콘솔에는 데이터가 오가는 과정을 출력했습니다.
만들고 끝났다. 하고 이 글을 올리면서 테스트 해보니 다른건 다 잘되는데
채팅내용 필드를 공백으로두고 send버튼을 누르면 그 클라이언트가 먹통이되네요ㅠㅠ
채팅내용이 있으면 상관은 없는데
아시는분은 댓글좀 남겨주세요ㅠㅠ
package chatNowTesting;
// 2014244057 PBL 11분반 컴퓨터공학과 2학년 이종민
// chatNowServer 먼저 실행후 Start 클릭 -> 그 다음 chatNowClient 실행후 Server메뉴에 Request를 보낸후 Account에서 로그인
// textfield에서 엔터치면 채팅되게하기 O, 로그인시 리스트에 추가하고 로그아웃하면 삭제하기(서버로 넘겨야함)
// 클라이언트에서 로그인 -> 아이디는 서버로 -> 서버에서 list 갱신
// 클라이언트에서 로그아웃 -> 아이디는 서버로 -> 서버에서 list 갱신
// 이미 로그인된 아이디는 다시 로그인 안되게 막기
// 지금 send parameter가 ID하나인데 ID로 txChat도 보내고 있음 이게 서버에 로그처럼 남기려고 전부 보냄
// 근데 멤버 리스트를 위해선 파라미터랑 txCHat을 나눠서 해야할것 같음
// send에 parameter를 하나 더 추가 하면 간단하게 해결 될듯
// 추가하다가 너무 스트레스 받아서 그냥 sned랑 receive를 두개로 나눔 // 안됌
// // 지금 로그인시 멤버추가까진 각 클라이언트에서 잘됌
// 근데 가장 큰 문제가 채팅을 치게되면 채팅 내용이 멤버에 추가됌....
// startClient 에서 receiveID, Chat을 둘다 받아야하는게 맞긴한데
// 이걸 어떻게 해결해야할지 막막
// 데이터를 한줄에 버튼이름, 아이디, 채팅내용을 넘김 StringTokenizer로 값을 구분시킴
// 서버까진 잘 받아지나 서버 receiveData에 있는 예외처리부분에서 에러를 내면서 로그인을 하게되면 바로 클라이언트와 연결이 종료...
// ??????? 207번 LINE에 예외를 EXCEPTION -> IOEXCEPTION으로 바꾸니 커넥션은 안끊김
// ???? 왜 되는지 이해할수가 없다 Exception이 모든 예외 처리 아닌가??
// 한 클라이언트에서 서버연결을 여러번 하는걸 방지해야하는데... 가능한가??
// 중복로그인도
// 생각을 잘못했다 서버에 연결되고 로그인을 하게 되면
// ID는 서버로 넘기고 서버에 리스트를 만들어서 로그인할때마다 거기에 넣어주고 누군가 연결을 하게 되면 그 아이디를 줘야하느데
// 꾸역꾸역 클라이언트에서 서버로 아이디 넘기고 넘어간걸 서버 벡터에 추가, 이미 있으면 아무것도 안함
// socket커넥트할때 아이디를 불러오고 싶었는데 못하겠어서 그냥 로그인하게되면 불러오게 함
// 근데... 로그인을 할 때 마다 a가 로그인하고 b가 로그인하면 a는 a, a, b가 보임...
// 데이터에는 중복아이디가 없이 잘 유지가 되는데 이걸 어떻게 해야할지
// 멤버는 추가하긴 해야하는데, 어떤 클라이언트가 로그인을 하던간에 자꾸 추가가 되니...
// 배열에 st2.nextToken을 넣고 그걸 또 따로 for문으로 멤버에 넣어주려고했는데...
// 메소드들을 나름 하나씩 내려가면서 확인도 했었는데 clear 메소드를 보고 뒤통수맞은기분 진짜 간단한걸 괜히 어렵게 접근한듯
// 서버와 연결이 끊기면 Member.clear 시켜줌
// 99퍼센트에서 이틀은 날린것같다
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.nio.channels.MembershipKey;
import java.awt.*;
import java.awt.List;
import java.util.*;
public class chatNowClient extends JFrame {
DefaultListModel<String> Member;
JFrame internalframe;
JList<String> liMem;
JTextArea txLog = new JTextArea();
JTextField txID = new JTextField("");
JTextField txPW = new JTextField("");
JTextField txChat = new JTextField("");
MyActionListener myBTListener = new MyActionListener();
Socket socket; // 클라이언트 통신을 위해 socket 필드 선언
void startClient() {
Thread thread = new Thread() { // 작업 스레드 생성 socket.connect와 receiveData와 블로킹이 일어나기 때문에 생성한다는데 잘 이해가 안감
@Override
public void run() { // run 메소드 재정의
try {
socket = new Socket(); // socket 생성
socket.connect(new InetSocketAddress("localhost", 7121)); // 로컬호스트, 7121포트로 연결요청
txLog.append("Connected at: " + socket.getRemoteSocketAddress() + "\n");
} catch(Exception e) {
txLog.append("CONNECT ERROR\n");
if(!socket.isClosed()) { // 예외발생했을때 소켓이 닫혀있지 안흥면
stopClient(); // startClient 종료
}
return;
}
receiveData(); // 호출
}
};
thread.start(); // 작업스레드 시작
}
void stopClient() {
try {
txLog.append("DISCONNECTED\n");
if(socket!=null && !socket.isClosed()) { // socket 필드가 NULL이 아니고 닫혀있지 않으면
socket.close(); // socket닫기
Member.clear(); // 서버와 연결이 끊겼을때 멤버 elements clear
}
} catch (IOException e) {}
}
void receiveData() {
while(true) { // 얼마나 들어올지 모르기 떄문에 while true
try {
byte[] Data = new byte[100];
String btNAME = null; // 버튼이름
String ID = null; // ID
String CHAT = null; // 채팅 내용
String serverMember = null; // server에서 보내준 member
StringTokenizer st, st2;
// data에서 버튼이름, 아이디, 채팅내용, member로 한번 나눈후 member를 다시 나눠야하기 떄문에 stringtokenizer두개 선언
InputStream isData = socket.getInputStream(); // socket으로부터 inputstream을 받음
int rbcData = isData.read(Data); // inputstream의 read 메소드 호출
if(rbcData == -1){
throw new IOException();
}
String DATA = new String(Data, 0, rbcData, "UTF-8"); // 데이터를 받았을때 UTF-8로 디코딩한 문자열을 얻음
System.out.println("Client receive DATA: " + DATA); // 확인용출력
st = new StringTokenizer(DATA, "$$"); // DATA를 "&&" 구분자로 나눔
while(st.hasMoreTokens()) { // 토큰이 없을때 까지
btNAME = st.nextToken();
ID = st.nextToken();
CHAT = st.nextToken();
serverMember = st.nextToken();
}
// 분명히 서버에서 byte로 형변환 후 client에서 받고 byte를 또 string으로 바꿨는데 뒤에 toString을 붙혀주지 않으면 replace가 안먹힘
// vector의 form [ex1, ex2, ex3] 중에 괄호를 지우고 싶어서 지워줌
String serverMemberTemp= serverMember.replace("[", "").toString(); // "[" -> 공백
serverMemberTemp = serverMemberTemp.replace("]", "").toString(); // "]" -> 공백
serverMemberTemp = serverMemberTemp.replace(", ", "$$").toString();// ", " -> $$
System.out.println("after using stringtokenizer and replace: " + serverMemberTemp); // 데이터 확인용 출력
st2 = new StringTokenizer(serverMemberTemp, "$$"); //serverMemberTemp를 구분자 "$$"로 나눔
Member.clear(); // 멤버 초기화? clear
while(st2.hasMoreTokens()) { // 토큰이 없을때까지
Member.addElement(st2.nextToken()); //토큰이 나올때마다 member에 추가
}
if(btNAME.equals("OK") && !ID.equals(null)) { // 버튼이름이 OK고 ID가 NULL이 아닐때
txLog.append("\"" + ID + "\"" + " Enter this room.\n");
}
else if (btNAME.equals("Logout") && !ID.equals(null)) { // 버튼이름이 logout이고 ID가 NULL이 아닐때
if(Member.contains(ID)) {//로그아웃할 아이디가 멤버에 포함되어있으면
Member.removeElement(ID); // 그 아이디 제거
}
else {} // 없으면 안함
txLog.append("\"" + ID + "\"" + " Left this room.\n");
}
else if((btNAME.equals("Send") || btNAME.equals("chatField")) && !ID.equals(null)) { // 버튼이름이 send거나 chatField이고 ID가 NULL이 아닐때
txLog.append("> " + ID + ": " + CHAT + "\n");
}
} catch (Exception e) {
stopClient();//예외발생하면 호출
break;
}
}
}
void sendData(String Name, String ID, String Chat) {
Thread thread = new Thread() { // 작업스레드 생성
@Override
public void run() { // run 재정의
try {
String data = Name + "$$" + ID + "$$" + Chat;
System.out.println("Client sendDATA: " + data); //데이터 확인용 출력
byte[] DATA = data.getBytes("UTF-8"); // 보낼 문자열에서 UTF-8로 인코딩한 바이트 배열을 얻는다.
OutputStream osData = socket.getOutputStream(); // socket에서 출력 스트림을 얻음
osData.write(DATA); // 바이트배열을 매개값으로 write메소드 호출
osData.flush(); // 출력스트림의 버퍼를 비우도록 호출
} catch(Exception e) {
stopClient(); // 예외발생하면 호출
}
}
};
thread.start();
}
public chatNowClient(){
//WindowBuilder로 컴포넌트 생성
super("Main Frame");
setTitle("chatNow");
setSize(500, 500);
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu mnNewMenu = new JMenu("Account");
menuBar.add(mnNewMenu);
JMenuItem mntmLogin = new JMenuItem("Login");
mnNewMenu.add(mntmLogin);
JMenuItem mntmLogout = new JMenuItem("Logout");
mnNewMenu.add(mntmLogout);
JMenu mnConnect = new JMenu("Connect");
menuBar.add(mnConnect);
JMenuItem mntmReq = new JMenuItem("Request the Connect");
mnConnect.add(mntmReq);
JMenuItem mntmDis = new JMenuItem("Disconnect the Connect");
mnConnect.add(mntmDis);
getContentPane().setLayout(null);
JButton btnSend = new JButton("Send");
btnSend.setBounds(407, 407, 75, 24);
getContentPane().add(btnSend);
JLabel lblMessages = new JLabel("Messages");
lblMessages.setBounds(22, 14, 69, 15);
getContentPane().add(lblMessages);
JLabel lblMembers = new JLabel("Members");
lblMembers.setBounds(333, 14, 57, 15);
getContentPane().add(lblMembers);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(22, 35, 299, 360);
getContentPane().add(scrollPane);
txLog.setEditable(false);
txLog.setLineWrap(true);
scrollPane.setViewportView(txLog);
JButton btnOK = new JButton("OK");
JButton btnCancel = new JButton("Cancel");
JLabel lbID = new JLabel("ID");
JLabel lbPW = new JLabel("PW");
internalframe = new JFrame("Login");
Container c= getContentPane();
txChat = new JTextField();
txChat.setBounds(22, 407, 384, 24);
getContentPane().add(txChat);
txChat.setColumns(10);
Container ic = internalframe.getContentPane();
ic.setLayout(new GridLayout(3,2));
ic.add(lbID);
ic.add(txID);
ic.add(lbPW);
ic.add(txPW);
ic.add(btnOK);
ic.add(btnCancel);
setVisible(true);
setResizable(false);
//액션리스너 추가
mntmLogin.addActionListener(myBTListener);
mntmLogout.addActionListener(myBTListener);
mntmReq.addActionListener(myBTListener);
mntmDis.addActionListener(myBTListener);
btnOK.addActionListener(myBTListener);
btnCancel.addActionListener(myBTListener);
btnSend.addActionListener(myBTListener);
txChat.addActionListener(myBTListener);
txChat.setActionCommand("chatField");
JScrollPane scrollPane_1 = new JScrollPane();
scrollPane_1.setBounds(333, 36, 149, 359);
getContentPane().add(scrollPane_1);
liMem = new JList<String>(); // JList를 String타입으로 선언
liMem = new JList<String>(new DefaultListModel<String>());// DefaultListModel로 리스트 컴포넌트 생성
Member = (DefaultListModel<String>)liMem.getModel();// 리스트 컴포넌트에서 리스트 모델을 얻어냄
scrollPane_1.setViewportView(liMem);
txChat.requestFocus();
}
public static void main(String[] args) {
chatNowClient c = new chatNowClient();
}
class MyActionListener implements ActionListener{
public void actionPerformed(ActionEvent e){
//menuItem들 button으로 cast가 안된다는 에러가 나와서 검색해서 해결
String name = e.getActionCommand(); // 버튼이 눌리면 버튼이름을 name에 저장
//사용자 ID, PW이 저장된 파일
File dataFile = new File("D:/login.txt");
String readData;
StringTokenizer st;
//ID, PW 빈칸검사를 위해 초기값설정
String loginID = null;
String loginPW = null;
loginID = txID.getText();
loginPW = txPW.getText();
String Chat = null;
if(name.equals("Request the Connect")) {// 서버연결 요청
startClient();
}
if(name.equals("Disconnect the Connect")) {// 서버연결 끊기
stopClient();
}
if(name.equals("OK")) {
boolean checkInfo = false; // 검증값
txPW.setText(""); // 비밀번호 텍스트 필드 초기화
if(loginID.equals("") || loginPW.equals("")) {//Login frame에서 txID 또는 txPW field가 빈칸이면
//ID, PW 확인하라는 MessageDialog 출력
JOptionPane.showMessageDialog(null, "Check your ID, PW please.", "LoginError", JOptionPane.ERROR_MESSAGE);
}
else {// ID, PW이 빈칸이 아니라면
//로그인 검증 부분
try {
//객체생성
BufferedReader br = new BufferedReader(new FileReader(dataFile));
while((readData = br.readLine()) != null) {//라인이 null값이 아닐때까지
st = new StringTokenizer(readData, " "); // dataFile인 login.txt를 구분자" "로 나누어서 저장
String txtID = st.nextToken();
String txtPW = st.nextToken();
if(loginID.equals(txtID) && loginPW.equals(txtPW)) {//입력한 ID txt파일 ID가 같고 입력한PW과 txt파일 PW이 같으면
checkInfo = true;//Login 검증 check값을 True로 바꾸고
//System.out.println(check);
break;//while break;
}
else {
checkInfo = false;// ID, PW이 같지 않다면
}
}
if(checkInfo == true) {// 만약 검증값이 ture이면
sendData(name, loginID, Chat);
internalframe.setVisible(false); //Loginframe을 숨김
}
else {//검증값이 false면
txLog.append("> Your Access is denied.\n");//출력
txID.setText("");
//ID, PW 확인하라는 MessageDialog 출력
JOptionPane.showMessageDialog(null, "Check your ID, PW please.", "LoginError", JOptionPane.ERROR_MESSAGE);
}
br.close();// BufferedReader 종료
}catch(IOException ie){//예외처리
System.out.println(ie.getMessage());
}
}
}
if(name.equals("Send") || name.equals("chatField")) { // 버튼이름이 send, chatField라면
if(loginID.equals("")) { // id가 빈칸일때
txLog.append("You need to login first.\n");
txChat.setText("");// 텍스트필드 초기화
}
else {
Chat = txChat.getText(); // 텍스트필드의 텍스트를 Chat에 저장
sendData(name, loginID, Chat);
txChat.setText("");// 텍스트필드 초기화
}
}
if(name.equals("Login")) {
if(internalframe.isVisible()==false){
internalframe.setBounds(150,100, 250,140);
internalframe.setVisible(true);
}
}
if (name.equals("Cancel")) {
txID.setText("");
txPW.setText("");
internalframe.setVisible(false);
}
if (name.equals("Logout")) {
loginID = txID.getText();
sendData(name, loginID, Chat);
if(loginID.equals("")) {
txLog.append("> You need to login.\n");
}
else {
loginID = null;
internalframe.setVisible(false);
}
txID.setText("");
txPW.setText("");
}
}
}
}
package chatNowTesting;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.DefaultListModel;
//import chatNowTesting.chatNowClient.MyActionListener;
import javax.swing.JButton;
import javax.swing.JScrollPane;
public class chatNowServer extends JFrame{
//
ExecutorService executorService; // thread pool 필드 선언
ServerSocket serverSocket; // serversocket 필드 선언
List<Client> connections = new Vector<Client>(); // 연결된 클라이언트를 저장할 connections 필드 선언
MyActionListener myBTListener = new MyActionListener();
JTextArea txLog = new JTextArea();
Vector<String> serverMember = new Vector<String>();
public chatNowServer(){
super("chatNowServer");
setResizable(false);
setVisible(true);
setSize(500, 377);
getContentPane().setLayout(null);
JButton btnInit = new JButton("Start");
btnInit.setBounds(0, 315, 520, 33);
getContentPane().add(btnInit);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(0, 0, 494, 314);
getContentPane().add(scrollPane);
scrollPane.setViewportView(txLog);
txLog.setLineWrap(true);
btnInit.addActionListener(myBTListener);
}
void startServer() {
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
//executorservice 객체를 얻기 위해 Executors.newFiexThreadPool() method 호출
//cpu 코어의 수만큼 스레드를 만듦
try {
serverSocket = new ServerSocket(); //serverSocket 객체 생성
serverSocket.bind(new InetSocketAddress("localhost", 7121)); // 127.0.0.1:7121과 binding
} catch(Exception e) {
if(!serverSocket.isClosed()) {//예외가 발생했을때 serversocket이 닫혀있지 않으면
stopServer(); // 호출(startServer를 종료)
}
return;
}
Runnable runnable = new Runnable() { // 연결 수락 작업을 Runnable로 정의
@Override
public void run() { // 메소드를 재정의
txLog.append("Start server\n");
while(true) { // 연결을 무한히 기다림
try {
Socket socket = serverSocket.accept(); // 클라이언트의 연결요청을 기다리고, accept 메소드 호출
String message = "[Accept Connect: " + socket.getRemoteSocketAddress() + ": " + Thread.currentThread().getName() + "]";
txLog.append(message + "\n");
Client client = new Client(socket); // 클라이언트 객체 생성
connections.add(client); // 생성된 클라이언트 객체를 connections 컬렉션에 추가
txLog.append("[Connect Count: " + connections.size() + "]\n");
//컬렉션에 저장된 클라이언트 객체의 수를 출력
} catch (Exception e) {
if(!serverSocket.isClosed()) { // 예외발생시 서버소켓이 닫혀있지않으면
stopServer(); // startServer를 종료하고
}
break; // 연결대기를 끝냄
}
}
}
};
executorService.submit(runnable); // 스레드풀 작업 스레드에서 연결 수락 작업을 처리하기 위해 submit 호출
}
void stopServer() {
try {
Iterator<Client> iterator = connections.iterator();// connections 컬렉션에서 반복자를 얻어냄
while(iterator.hasNext()) { // 반복자를 반복함
Client client = iterator.next(); // 반복자로부터 클라이언트를 하나씩 얻음
client.socket.close(); // 클라이언트가 가지고 있는 socket을 닫음
iterator.remove();// connections 컬렉션에서 클라이언트 제거
}
if(serverSocket!=null && !serverSocket.isClosed()) { // serversocket이 NULL이 아니고 닫혀있지 않다면
serverSocket.close(); // 닫기
}
if(executorService!=null && !executorService.isShutdown()) { //executorservice가 NULL이 아니고 닫혀있지 않다면
executorService.shutdown(); //executorservice 종료
}
txLog.append("Stop server\n");
} catch (Exception e) { }
}
class Client { //내부 클래스 선언
Socket socket; // 필드선언
Client(Socket socket){ // 클라이언트 생성자 생성
this.socket = socket; // 매개값으로 받은 socket을 필드값으로 저장
receiveData(); // 메소드 호출
}
void receiveData() {
Runnable runnable = new Runnable() { // 클라이언트로부터 데이터를 받는 작업을 Runnable로 정의
@Override
public void run() { // 메소드 재정의
try {
StringTokenizer st; // data를 나누기 위해 stringtokenizer 사용
while(true) { // 작업 반복
byte[] Data = new byte[100]; // 받은 데이터를 저장할 공간 선언
String btNAME = "";// 버튼이름
String ID = ""; // 아이디
String CHAT = ""; // 채팅 내용
InputStream isDATA = socket.getInputStream(); // socket으로부터 inputstream을 얻음
int rbcData = isDATA.read(Data); //inputstream의 read메소드 호출. 클라이언트가 데이터를 보내기 전까지 블로킹되고,
// 데이터를 받으면 Data에 저장한 후 받은 바이트 개수를 rbcData에 저장
if(rbcData == -1) {
throw new IOException();
}
String message = "[Request handle: " + socket.getRemoteSocketAddress() + ": " + Thread.currentThread().getName() + "]";
txLog.append(message + "\n");
String DATA = new String(Data, 0, rbcData, "UTF-8"); // UTF-8로 디코딩한 문자열을 DATA에 저장
System.out.println("Server receive DATA:" + DATA);
//txLog.append("Server receive DATA:" + DATA + "\n");
st = new StringTokenizer(DATA, "$$");
// 받은 데이터 DATA를 구분자"$$"로 나눔
while(st.hasMoreTokens()) {//토큰이 존재하지 않을때 까지
btNAME = st.nextToken();
ID = st.nextToken();
CHAT = st.nextToken();
}
if(btNAME.equals("OK")) { // 버튼이름이 OK라면
txLog.append(ID + "> " + "Enter this room(server sended).\n");//출력
if(serverMember.contains(ID)) {} // 만약 serverMember에 ID가 이미 포함되어 있으면 아무것도 하지않고
else {
serverMember.addElement(ID); // 없으면 아이디를 추가
}
}
else if(btNAME.equals("Logout")) { // 버튼이름이 Logout이라면
txLog.append(ID + "> " + "Left this room(server sended).\n");//출력
serverMember.removeElement(ID); // serverMember element중 ID를 제거
}
else if (btNAME.equals("Send") || btNAME.equals("chatField")) { // 버튼이름이 send거나 chatField이면
txLog.append(ID + "> " + CHAT + "\n");
}
System.out.println("serverMember Elements: " + serverMember); // 로그용출력
for(Client client : connections) { // connections에 저장된 클라이언트 하나하나에게
client.sendData(btNAME, ID, CHAT, serverMember); // 버튼이름, id, 채팅내용, vector serverMember Elements를 매개값으로 넘겨줌
}
}
} catch(IOException e) {
try {
connections.remove(Client.this); //connections 컬렉션에서 예외가 발생한 클라이언트 제거
String message = "[Client Disconnected: " + socket.getRemoteSocketAddress() + ": " + Thread.currentThread().getName() + "]";
txLog.append(message + "\n");
socket.close();
} catch (IOException e2) {
txLog.append(e2.getMessage() + "\n");
}
}
}
};
executorService.submit(runnable);// 스레드풀에서 작업처리를 위해 submit 호출
}
void sendData(String Name, String ID, String Chat, Vector<String> serverMember) {
Runnable runnable = new Runnable() { // 데이터를 클라이언트로 보내는 작업을 Runnable로 생성
@Override
public void run() { //run 재정의
try {
String data = Name + "$$" + ID + "$$" + Chat + "$$" + serverMember;
// 매개값으로 받은 데이터들을 client에서 stringtokenizer사용을 위해 사이사이에 구분자 $$를 삽입
System.out.println("Server send DATA:" + data); // 확인용출력
//txLog.append("Server send DATA:" + data + "\n");
byte[] DATA = data.getBytes("UTF-8");// 보낼 문자열로부터 UTF-8로 인코딩한 바이트 배열을 얻는다.
OutputStream osData = socket.getOutputStream(); // socket에서 출력스트림을 얻음
osData.write(DATA);// 바이트 배열을 매개값으로 write 호출
osData.flush(); // 출력 스트림의 내부 버퍼를 비우기 위해 호출
} catch(Exception e) {
try {
String message = "[Client communication error: " + socket.getRemoteSocketAddress() + ": " + Thread.currentThread().getName() + "]";
txLog.append(message + "\n");
connections.remove(Client.this);//connections 컬렉션에서 예외가 발생한 클라이언트 제거
socket.close(); // socket닫음
} catch (IOException e2) {}
}
}
};
executorService.submit(runnable);
}
}
public static void main(String[] args) {
chatNowServer cs = new chatNowServer();
}
class MyActionListener implements ActionListener{
public void actionPerformed(ActionEvent e){
JButton b = (JButton)e.getSource();
if(b.getText().equals("Start")) {
startServer();
b.setText("Stop");
}
else {
stopServer();
b.setText("Start");
}
}
}
}
'Java > for Class, Project' 카테고리의 다른 글
javacv 얼굴감지, 얼굴인식 예제 스윙, javaFX opencv 한글 (javacv Face Detection, Recognizer Example on swing, javafx) (0) | 2017.12.08 |
---|---|
은행권 공동 플랫폼 API 사용에 대한 정보입니다. (6) | 2017.11.08 |
PBL 프로젝트 문서 관련 요구 사항 (0) | 2017.11.06 |
Java Client, Server data communication example 클라이언트, 서버 데이터통신 예제(이것이 자바다) (0) | 2017.11.01 |
Java client, server connect example 클라이언트, 서버 연결 예제 only connect (0) | 2017.11.01 |
티스토리 방명록
- Total
- Today
- Yesterday
Contact: j0n9m1n1@gmail.com