티스토리 뷰

반응형

기본 사용법은 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");

        }

}

}

}

 

댓글

티스토리 방명록

최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday