ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JAVA] Socket을 이용한 간단한 채팅 프로그램
    JAVA 2012. 2. 26. 22:57

    Head First Java를 훓어 보는 중이다.. 15장에 간단한 채팅 프로그램이 있어 그냥 돌려봄..

    간단하다~
    자바는 입출력 스트림만 잘 체이닝하면 소켓이던 DB던 파일이던 머던간에 그리 어려움은 없어 보인다.

    서버..
    package chap15.practice;

    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.Iterator;

    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.ScrollPaneConstants;

    public class VerySimpleChatServer {
     
     ArrayList clientOutputStreams;
     JTextArea status; // 서버상태를 표시할 영역
     
     public class ClientHandler implements Runnable {
      BufferedReader reader;
      Socket sock;
      
      public ClientHandler(Socket clientSocket) {
       try {
        sock = clientSocket;
        InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
        reader = new BufferedReader(isReader);
        
       } catch (Exception e) {e.printStackTrace();}
      }
      
      public void run() {
       String message;
       try {
        // 메시지가 올때마다 접속한 채팅클라이언트에 모두 전달
        while((message = reader.readLine()) != null) {
         System.out.println("read : " + message);
         tellEveryone(message);
        }
       } catch (Exception e) {e.printStackTrace();}
      }
      
     }
     
     public static void main(String[] args) {
      new VerySimpleChatServer().start();
     }
      
     public void start() {
      JFrame frame = new JFrame("server status");
      JPanel mainPanel = new JPanel();
      status = new JTextArea(15,40);
      status.setLineWrap(true); //자동 개행
      status.setWrapStyleWord(true); //행을 넘길 때 행의 마지막 단어가 두행에 걸쳐 나뉘지 않도록 하기
      status.setEditable(false);
      status.setVisible(true);
      JButton exitButton = new JButton("Exit");
      exitButton.addActionListener(new ExitButtonListener());
      JScrollPane qScroller = new JScrollPane(status);
      qScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); //수직 스크롤바 표시 정책 : 항상 보여주기
      qScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);// 수평 스크롤바 표시 정책 : 항상 보여주기
      mainPanel.add(qScroller);
      mainPanel.add(exitButton);
      status.append("Chat Server Start..\n");
      
      frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
      frame.setSize(500, 500);
      frame.setVisible(true);
      
      go();
     }
     
     public void go() {
        
      clientOutputStreams = new ArrayList();
      try {
       ServerSocket serverSock = new ServerSocket(5000);
       
       // 계속 새로운 채팅 클라이언트를 accept
       while(true) {
        Socket clientSocket = serverSock.accept();
        PrintWriter writer = new PrintWriter(clientSocket.getOutputStream());
        clientOutputStreams.add(writer);
        
        Thread t = new Thread(new ClientHandler(clientSocket));
        t.start();
        //System.out.println("got a connection" + clientSocket.getPort());
        status.append("got a connection : " + clientSocket.getPort() + "\n");
       }
      } catch(Exception e) {
       e.printStackTrace();
      }
     }
     
     public class ExitButtonListener implements ActionListener {
      public void actionPerformed(ActionEvent ev) {
       try {
        System.exit(0);
       } catch(Exception e) {
        e.printStackTrace();
       }
      }
     }
     
     public void tellEveryone(String message) {
      Iterator it = clientOutputStreams.iterator();
      while(it.hasNext()) {
       try {
        PrintWriter writer = (PrintWriter) it.next();
        writer.println(message);
        writer.flush();
       } catch(Exception e) {
        e.printStackTrace();
       }
      }
     }
    }




    클라이언트~
    package chap15.practice;

    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.Socket;

    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    import javax.swing.ScrollPaneConstants;

    public class SimpleChatClient {

     JTextArea incoming; // 서버로부터 읽어온 메시지를 표시할 영역
     JTextField outgoing; // 서버로보낼 메시지를 입력할 영역
     BufferedReader reader; // 서버로부터 온 메시지를 읽어드릴 읽기버퍼
     PrintWriter writer; // 메시지를 소켓 스트림에 써줄 쓰기 스트림
     Socket sock; // 소켓
     
     public static void main(String[] args) {
      SimpleChatClient client = new SimpleChatClient();
      client.go();
     }
     
     public void go() {
      // 채팅창 UI
      JFrame frame = new JFrame("Ludicrously Simple Chat Client");
      JPanel mainPanel = new JPanel();
      incoming = new JTextArea(15,40);
      incoming.setLineWrap(true); //자동 개행
      incoming.setWrapStyleWord(true); // 행을 넘길 때 행의 마지막 단어가 두행에 걸쳐 나뉘지 않도록 하기
      incoming.setEditable(false);
      incoming.setVisible(true);
      JScrollPane qScroller = new JScrollPane(incoming);
      qScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); //수직 스크롤바 표시 정책 : 항상 보여주기
      qScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);// 수평 스크롤바 표시 정책 : 항상 보여주기
      outgoing = new JTextField(20);
      JButton sendButton = new JButton("Send");
      sendButton.addActionListener(new SendButtonListener());
      JButton exitButton = new JButton("Exit");
      exitButton.addActionListener(new ExitButtonListener());
      mainPanel.add(qScroller);
      mainPanel.add(outgoing);
      mainPanel.add(sendButton);
      mainPanel.add(exitButton);
      incoming.append("notice : UI 초기화\n");
      
      // 소켓 통신 초기화
      setUpNetWorking();
      incoming.append("notice : 소켓 통신 초기화\n");
      incoming.append("notice : 채팅에 입장하셨습니다.\n\n");
      
      // 읽기 쓰레드 생성, 시작
      Thread readerThread = new Thread(new IncomingReader());
      readerThread.start();
      
      // UI visual(정렬,크기) 설정
      frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
      frame.setSize(500, 500);
      frame.setVisible(true);
     }
     
     private void setUpNetWorking() { // 클라이언트와 서버간 통신할 준비
      try {
       
       // 소켓 객체 생성
       sock = new Socket("127.0.0.1", 5000);
       
       // 버퍼리더 + 입력스트림리더 + 소켓입력스트림 체이닝
       InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());
       reader = new BufferedReader(streamReader);
       
       // printwriter + 소켓출력스트림 체이닝
       writer = new PrintWriter(sock.getOutputStream());
       
       System.out.println("networking established");
      } catch (Exception e) {
       e.printStackTrace();
      }
     }
     
     // Send 버튼 리스너
     public class SendButtonListener implements ActionListener {
      
      // 버튼 눌리면
      public void actionPerformed(ActionEvent ev) {
       try {
        writer.println(outgoing.getText()); // outgoing 영역의 텍스트를 가져와 writer에 쓴다.
        writer.flush(); // 버터링 하짐 말고 바로 flush
       } catch(Exception ex) {
        ex.printStackTrace();
       }
       outgoing.setText(""); //쓰고 나서 outgoing 영역을 비운다.
       outgoing.requestFocus(); //포커스를 텍스트창에 놓는다.
      }
     }
     
     public class ExitButtonListener implements ActionListener {
      public void actionPerformed(ActionEvent ev) {
       try {
        System.exit(0);
       } catch(Exception e) {
        e.printStackTrace();
       }
      }
     }
     
     public class IncomingReader implements Runnable {
      public void run() {
       String message;
       try {
        while ((message = reader.readLine()) != null) {
         System.out.println("read " + message);
         incoming.append(message + "\n");
        }    
       } catch (Exception e) {e.printStackTrace();}
      }
     }
    }


Designed by Tistory.