LeReve 2013. 3. 11. 12:32

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;


public class Server extends JFrame {
 private JTextField enterField; // 사용자로부터 메시지를 받음
 private JTextArea displayArea; // 사용자에게 정보를 보여줌
 private ObjectOutputStream output; // 클라이언트에 보낼 출력 스트림
 private ObjectInputStream input; // 클라이언트로부터 받을 입력 스트림
 private ServerSocket server; // 서버 소켓
 private Socket connection; // 클라이언트와 연결하는 소켓
 private int counter = 1; // 연결 횟수의 카운터
 
 //GUI를 설정함
 
 public Server(){
  super("Server");
  enterField = new JTextField(); // enterField를 생성함
  enterField.setEditable(false);
  enterField.addActionListener(
    new ActionListener() {
     //클라이언트에 메시지를 보냄
     @Override
     public void actionPerformed( ActionEvent event ) {
      // TODO Auto-generated method stub

      sendData(event.getActionCommand());
      enterField.setText("");
     } //actionperformed 메소드 끝
    } // 익명 내부 클래스 끝
   ); // addActionListener 호출 끝
  
  add( enterField, BorderLayout.NORTH);
  
  displayArea = new JTextArea(); // displayArea를 생성함
  add( new JScrollPane(displayArea), BorderLayout.CENTER);
  
  setSize(300, 150); //윈도의 크기를 설정함
  setVisible(true); // 윈도를 표시함
 } // Server 생성자 끝
 
 public void runServer(){
  try{ // 서버가 연결 요청을 받도록 설정하고, 연결을 처리함
   server = new ServerSocket(12345, 100); // ServerSocket을 생성함
   
   while(true){
    try{
     waitForConnection(); // 연결 요청을 기다림
     getStreams(); // 입/출력 스트림을 얻어옴
     processConnection(); // 연결 처리를 수행함
    } // try 블록 끝
    catch(EOFException eofException){
     displayMessage("\nServer terminated connection");
    } // catch 블록 끝
    finally{
     closeConnection(); // 연결을 끊음
     counter++;
    } // finally 블록 끝
   } // while 문 끝
  } // try 블록 끝
  catch(IOException ioException){
   ioException.printStackTrace();
  } // catch 블록 끝
 } // runServer 메소드 끝
 
 // 연결 요청이 도착할 때까지 기다리고, 도착하면 연결 정보를 표시함
 private void waitForConnection() throws IOException{
  displayMessage("Waiting for connection\n");
  connection = server.accept(); // 서버가 연결 요청을 승인하게 함
  displayMessage("Connection "+counter+" received from: "+connection.getInetAddress().getHostName());
 } // waitForConnection 메소드 끝
 
 // 데이터를 주고받을 스트림을 얻어옴
 private void getStreams() throws IOException{
  //객체에 대한 출력 스트림을 설정함
  output = new ObjectOutputStream(connection.getOutputStream());
  output.flush(); // 헤더 정보를 보내기 위해 출력 버퍼를 비움
  
  // 객체에 대한 입력 스트림을 설정함
  input = new ObjectInputStream(connection.getInputStream());
  
  displayMessage("\nGot I/O streams\n");
 } // getStreams 메소드 끝
 
 // 클라이언트와 연결을 처리함
 private void processConnection() throws IOException{
  String message = "Connection successful";
  sendData( message ); // 연결 요청이 성공했다는 메시지를 클라이언트에 보냄
  
  // enterField를 활성화해서 서버 사용자가 메시지를 보낼 수 있도록 함
  setTextFieldEditable(true);
  
  do{ // 클라이언트가 서버에 보낸 메시지를 처리함
   try{
    message = (String) input.readObject(); // 새로운 메시지를 읽음
    displayMessage("\n" + message); // 메시지를 표시함
   } // try 블록 끝
   catch(ClassNotFoundException classNotFoundException){
    displayMessage("\nUnknown object type received");
   } // catch 블록 끝
  }while(!message.equals("CLIENT>>> TERMINATE"));
 } // processConnection 메소드 끝
 
 // 스트림과 소켓의 연결을 끊음
 private void closeConnection(){
  displayMessage("\nTerminating connection\n");
  setTextFieldEditable(false); // enterfield를 비활성화함
  
  try{
   output.close(); // 출력 스트림을 닫음
   input.close(); //입력 스트림을 닫음
   connection.close(); // 소켓을 닫음
  } // try 블록 끝
  catch(IOException ioException){
   ioException.printStackTrace();
  } // catch 블록 끝
 } // closeConnection 메소드 끝
 
 // 클라이언트에 메시지를 보냄
 private void sendData(String message){
  try{ // 클라이언트에 객체를 보냄
  output.writeObject("SERVER>>> " + message);
  output.flush(); // 클라이언트에 보낼 출력 버퍼를 비움
  displayMessage("\nSERVER>>> " + message);
  } // try 블록 끝
  catch(IOException ioException){
   displayArea.append("\nError writing object");
  } // catch 블록 끝
 } // sendData 메소드 끝
 
 // 이벤트 전달 스레드에 있는 displayArea를 조작함
 private void displayMessage( final String messageToDisplay){
  SwingUtilities.invokeLater(
    new Runnable() {     
     @Override
     public void run() { // displayArea를 갱신함
      // TODO Auto-generated method stub
      displayArea.append(messageToDisplay); // message를 추가함     
     } // run 메소드 끝
    } // 익명 내부 클래스 끝
  ); // SwingUtilities.invokeLater 호출 끝
 } // displayMessage 메소드 끝
 
 // 이벤트 전달 스레드에 있는 enterField를 조작함
 private void setTextFieldEditable(final boolean editable){
  SwingUtilities.invokeLater(
    new Runnable() {
     @Override
     public void run() { // enterField의 편집 활성화를 설정함
      // TODO Auto-generated method stub
      enterField.setEditable(editable);
     } // run 메소드 끝
    } // 내부 클래스 끝
  ); // SwingUtilities.invokeLater 호출 끝
 } // setTextFieldEditable 메소드 끝

} // Server 클래스 끝