E001 // 클라이언트에서 연결 요청하면 서버는 네트워크 연결 초기화
E002 // 서버 데이터가 도착할 때까지 계속 대기
E003 // (수신전용스레드와 별개로) 메인 스레드 N41 이후 실행중
E004 // 대화를 입력할 때까지 계속 대기
E005 // '안녕하세요' 입력
E006 // 서버로 데이터([CHAT] [클라이언트2]안녕하세요) 전송
E007 // 서버에서 보낸 데이터([CHAT] [클라이언트1]반갑습니다) 도착
E008 // 프로그램 닫기(우측상단 X) 선택
E009 // 메인스레드와 수신전용스레드가 모두 종료하여 프로그램 종료
// 파일명 : ./Chapter18/ChatGUIClient.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import chat.ChatNetworkPanel;
// 채팅 GUI 클라이언트
public class ChatGUIClient
{
1 public static void main( String[] args ) {
String serverIP = "localhost";
2 ChatNetworkPanel panel =
3 new ChatNetworkPanel( serverIP );
JFrame frame = new JFrame( "채팅(클라이언트)" );
frame.getContentPane().add( panel );
frame.addWindowListener( new WindowAdapter() {
Wb public void windowClosing( WindowEvent event ) {
W1 panel.close();
We }
} );
frame.setPreferredSize( new Dimension( 320, 445 ) );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.setVisible(true);
4 }
}
// 파일명 : ./src/chat/ChatNetworkPanel.java
package chat;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import network.Network;
// 채팅 네트워크 패널 클래스
public class ChatNetworkPanel extends JPanel implements ActionListener, Runnable
{
private JTextArea chatWindow;
private JTextField inputField;
private Network network;
private String id;
private final String header = "[CHAT] ";
// 채팅 패널 초기화
CN1b public ChatNetworkPanel() {
// 채팅창
chatWindow = new JTextArea();
chatWindow.setBackground( Color.lightGray );
chatWindow.setEditable( false );
chatWindow.setLineWrap( true );
// 채팅창이 길어지면 스크롤 활성화
JScrollPane scroll = new JScrollPane( chatWindow );
scroll.setPreferredSize( new Dimension( 290, 360 ) );
add( scroll );
// 입력창
inputField = new JTextField();
inputField.setPreferredSize( new Dimension( 290, 30 ) );
inputField.addActionListener( this );
inputField.requestFocus();
add( inputField );
setVisible( true );
CN1e }
// 채팅 네트워크 클라이언트 초기화
CN2b public ChatNetworkPanel( String serverIP ) {
// 채팅 패널 초기화
CN21 this();
// 네트워크 초기화
CN22 network =
CN23 new Network();
CN24 network.connectAsClient( serverIP, this );
// 대화명 입력
id = "[" + JOptionPane.showInputDialog( this, "아이디를 입력해주세요.", "아이디" ) + "]";
network.write( header + id + "님이 들어오셨습니다" );
CN2e }
// 대화 내용 입력시 상대편에게 전송
@Override
CN3b public void actionPerformed( ActionEvent event ) {
// 입력한 대화 내용 읽기
String message = inputField.getText();
// 상대편에게 네트워크로 대화 내용 전송
CN31 network.write( header + id + message );
inputField.setText( "" );
CN3e }
// 대화 내용 도착시 채팅 화면 업데이트
@Override
CN4b public void run() {
// 상대편이 네트워크로 보낸 데이터 읽기
CN41 for ( String message = null; ( message =
CN42 network.read() )
!= null; ) {
// 채팅 프로그램 대화 내용이 아니면 메시지 무시
if ( !message.contains( header ) )
continue;
// 채팅 화면에 읽은 대화 내용 쓰기
CN43 chatWindow.append( message.substring( header.length() ) + "\n" );
chatWindow.setCaretPosition( chatWindow.getText().length() );
CN44 }
CN4e }
// 채팅 네트워크 종료
CN5b public void close() {
network.write( header + " " + id + "님이 나가셨습니다" );
// 네트워크 종료
CN51 network.close();
CN5e }
}
// 파일명 : ./src/network/Network.java
package network;
import java.io.*;
import java.net.*;
// 네트워크 연결 및 입출력 클래스
public class Network
{
public static final int serverPort = 7700;
protected ServerSocket serverSocket;
protected Socket socket;
private BufferedReader in;
private PrintWriter out;
private Thread waitForCounterpart;
// 네트워크 클래스 초기화
N1b public Network() {
serverSocket = null;
socket = null;
in = null;
out = null;
waitForCounterpart = null;
N1e }
// 네트워크 서버 연결 초기화
N2b public void connectAsServer( Runnable obj ) {
try {
// 서버 소켓 연결
serverSocket = new ServerSocket( serverPort );
// 클라이언트에서 서버로 연결 요청시 연결 활성화
N21 socket =
N22 serverSocket.accept();
// 네트워크 입출력 연결 후 데이터가 도착할 때까지 대기
N23 connectInOut( obj );
} catch ( Exception e ) {
e.printStackTrace();
}
N2e }
// 네트워크 클라이언트 연결 초기화
N3b public void connectAsClient( String serverIP, Runnable obj ) {
try {
// 클라이언트에서 서버로 연결 요청
N31 socket =
N32 new Socket( serverIP, serverPort );
// 네트워크 입출력 연결 후 데이터가 도착할 때까지 대기
N33 connectInOut( obj );
} catch ( Exception e ) {
e.printStackTrace();
}
N3e }
// 네트워크 입출력 초기화
N4b public void connectInOut( Runnable obj ) {
try {
// 네트워크 입출력 연결
in = new BufferedReader( new InputStreamReader( socket.getInputStream() ));
out = new PrintWriter( socket.getOutputStream(), true );
// 네트워크에 데이터가 도착할 때까지 대기 시작
waitForCounterpart = new Thread( obj );
N41 waitForCounterpart.start();
} catch ( Exception e ) {
e.printStackTrace();
}
N4e }
// 상대편이 네트워크로 보낸 데이터 읽기
N5b public String read() {
try {
if ( this.isConnecting() == true )
N51 return
N52 in.readLine();
} catch ( Exception e ) {
e.printStackTrace();
}
return null;
N5e }
// 상대편에게 네트워크로 데이터 전송
N6b public void write( String data ) {
try {
if ( this.isConnecting() == true )
N61 out.println( data );
} catch ( Exception e ) {
e.printStackTrace();
}
N6e }
// 네트워크 연결 상태 확인
public boolean isConnecting() {
if ( ( socket != null )
&& ( in != null )
&& ( out != null )
&& ( waitForCounterpart != null )
&& ( waitForCounterpart.getState() != Thread.State.TERMINATED ) )
return true;
else
return false;
}
// 네트워크 종료
N7b public void close() {
try {
if ( waitForCounterpart != null ) {
waitForCounterpart.interrupt();
waitForCounterpart = null;
}
if ( in != null ) {
in.close();
in=null;
}
if ( out != null ) {
out.flush();
out.close();
out = null;
}
if ( socket != null ) {
socket.close();
socket = null;
}
if ( serverSocket != null ) {
serverSocket.close();
serverSocket = null;
}
} catch ( Exception e ) {
e.printStackTrace();
}
N7e }
}