1. TCP 소켓 프로그램 예제의 흐름
(1) 서버 소켓 생성
(2) 서버 소켓으로 청취
(3) 클라이언트 소켓 생성
(4) (서버, 클라이언트) 소켓을 이용하여 스트림 생성
(5) 클라이언트 메시지 전송
(6) 서버 메시지 읽음
(7) 서버 메시지 전송
(8) 클라이언트 메시지 읽음
(9) (서버, 클라이언트) 소켓 종료
* 본 예제에서는 클라이언트가 메시지를 한 번만 전송할 수 있는데, 만약 클라이언트가 계속 메시지를 전송하기 위해서는 서버쪽에 스레드를 생성해야 한다.
EchoServer.java
package socket.echo;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;
import java.net.ServerSocket; //ServerSocket 클래스는 TCP서버소켓을 의미한다.
import java.net.Socket;
public class EchoServer {
private BufferedReader bufferR;
private BufferedWriter bufferW;
private InputStream is;
private OutputStream os;
private ServerSocket serverS;
public EchoServer(int port){
try{
//ServerSocket 객체를 3000번 포트를 이용하여 생성.
serverS = new ServerSocket(port);
}catch(IOException ioe){
ioe.printStackTrace();
System.exit(0);
}
while(true){
try{
System.out.println("클라이언트의 요청을 기다리는 중");
//accept() 메서드를 이용하여 클라이언트의 TCP커넥션(클라이언트에서 Socket객체를 생성하는 것)을 기다리고 있다.
//accept() 메서드는 클라이언트의 Socket객체가 생성될 때까지 블로킹 되고 있다가 클라이언트의 Socket객체가 생성되면 서버에서 클라이언트와 통신할 수 있는 Socket 객체를 리턴하게 된다.
//accept() 메서드의 유효시간이 지나면 java.net.SocketTimeoutException이 발생하는데, 이 예외가 발생하더라도 ServerSocket객체는 계속 유효하다.
//실험결과 accept() 메서드가 Socket 객체를 리턴하지 않는 한 while문의 루프도 돌아가지 않았다.
Socket tcpSocket = serverS.accept();
System.out.println("클라이언트의 IP주소 : "+tcpSocket.getInetAddress().getHostAddress());
is = tcpSocket.getInputStream(); //'소켓으로부터' 읽고
os = tcpSocket.getOutputStream(); //'소켓에' 쓴다.
bufferR = new BufferedReader(new InputStreamReader(is));
bufferW = new BufferedWriter(new OutputStreamWriter(os));
String message = bufferR.readLine();
System.out.println("수신메시지 : "+message);
message += System.getProperty("line.separator"); //엔터키넣기
bufferW.write(message);
bufferW.flush();
bufferR.close();
bufferW.close();
tcpSocket.close();
}catch(IOException ie){
ie.printStackTrace();
}
}
}
public static void main(String[] args){
new EchoServer(3000);
}
}
EchoClient.java
package socket.echo;
import java.io.*;
import java.net.*;
public class EchoClient {
private String ip;
private int port;
private String str;
BufferedReader file;
//생성자
public EchoClient(String ip, int port) throws IOException{
this.ip = ip;
this.port = port;
//Socket객체를 생성한다. Socket객체가 생성되면 서버와 TCP 커넥션이 이루어지게 된다. 동시에 서버의 accept()메서드는 클라이언트와 통신할 수 있는 Socket객체를 반환하게 된다. 따라서 클라이언트의 Socket객체와 서버의 Socket객체가 각각의 스트림을 이용하여 통신할 수 있게 된다.
Socket tcpSocket = getSocket(); //사용자 메서드
OutputStream os_socket = tcpSocket.getOutputStream(); //소켓에 쓰고
InputStream is_socket = tcpSocket.getInputStream(); //소켓에서 읽는다
BufferedWriter bufferW = new BufferedWriter(new OutputStreamWriter(os_socket));
BufferedReader bufferR = new BufferedReader(new InputStreamReader(is_socket));
System.out.print("입력 : ");
//소켓으로부터 읽는 것이 아니라 키보드로부터 읽는 또 하나의 BufferedReader
file = new BufferedReader(new InputStreamReader(System.in));
str = file.readLine();
str += System.getProperty("line.separator");
bufferW.write(str);
bufferW.flush();
str = bufferR.readLine();
System.out.println("Echo Result : "+str);
file.close();
bufferW.close();
bufferR.close();
tcpSocket.close();
}
public Socket getSocket(){ //호스트의 주소와 포트를 사용, 소켓을 만들어 리턴하는 사용자 메서드
Socket tcpSocket = null;
try{
//원격 호스트(여기서는 서버)의 주소와 포트(여기서는 멤버변수)를 사용하여 Socket객체를 생성한다.
//호스트를 찾을 수 없거나, 서버의 포트가 열려 있지 않은 경우에는 UnknownHostException 이 발생하고,
//네트워크의 실패, 또는 방화벽 때문에 서버에 접근할 수 없을 때에는 IOException 이 발생할 수 있다.
tcpSocket = new Socket(ip, port);
}catch(IOException ioe){
ioe.printStackTrace();
System.exit(0);
}
return tcpSocket;
}
public static void main(String[] args)throws IOException{
new EchoClient("localhost", 3000);
}
}
- 출처 : [한빛미디어] 자바 5.0 프로그래밍 -