시소당
클라이언트에서 서버로 문자열을 송신하는 프로그램을 제작해보자. 클라이언트에서 서버로 단방향 통신만 가능하다. 클라이언트 측의 소켓과 서버 측의 소켓이 연결되었을 때 클라이언트 측 소켓의 출력 스트림으로 데이터를 전송하면 서버 측 소켓의 입력 스트림으로부터 데이터를 수신하면 된다. 이때 채팅 프로그램과 같이 한 라인 단위로 입·출력하기 위해 자주 사용되는 PrintWriter와 BufferedReader를 이용하자. 다음 그림은 클라이언트에서 서버 쪽으로 데이터의 흐름을 표현한 것이다.
[그림 21-6] 클라이언트 -> 서버
PrintWriter 대신에 BufferedWriter를 사용할 수도 있으나 PrintWriter는 자동 flush가 되기 때문에 더 좋다. flush기능을 사용하지 않으면 데이터가 제때 송신하지 않을 수 있으므로 주의해야할 것이다.
서버의 소스파일 이름은 "Server2.java"이고, 클라이언트의 소스파일 이름은 "Client2.java"로 하여 실제로 구현해 보자.
문자열 수신 서버
단일 클라이언트를 위한 서버는 그렇게 복잡하지 않다. 제작할 서버 프로그램은 클라이언트 측 소켓과 연결된 소켓으로부터 문자열을 읽어와 화면에 그대로 보여준다. 그러나 클라이언트 측으로는 어떤 데이터도 전송하지 않는다.
서버는 다음과 같은 과정을 반복한다.
1. 클라이언트를 기다린다.
2. 클라이언트와 연결한다.
3. 클라이언트가 연결을 끊기 전까지 문자열을 수신한다.
4. 클라이언트가 연결을 끊는다.
5. 1번을 실행한다.
클라이언트와 연결된 소켓의 입력 스트림을 얻는 과정은 다음과 같다.
Socket socket=server.accept(); // 클라이언트와 연결된 소켓
InputStream is=socket.getInputStream(); // 소켓의 InputStream을 얻는다.
InputStreamReader isr=new InputStreamReader(is);
BufferedReader reader= new BufferedReader(isr); // 캐릭터 스트림
다음 문자열 수신 서버의 소스이다.
Server2.java
import java.net.*;
import java.io.*;
public class Server2{
private BufferedReader reader; // 입력을 담당한다.
private ServerSocket server; // 서버소켓
private Socket socket; // 소켓
public Server2(){} // 디폴트 생성자
void startServer(){ // 서버 실행 메소드
try{
server=new ServerSocket(7777); // 서버소켓을 생성한다.
System.out.println("서버소켓이 생성되었습니다.");
while(true){
System.out.println("클라이언트를 기다립니다.");
socket=server.accept(); // 클라이언트가 접속하면 socket과 연결한다.
System.out.println("클라이언트와 연결되었습니다.");
// socket의 입력 스트림을 얻는다.
reader=new BufferedReader(
new InputStreamReader( socket.getInputStream() ));
getMessage(); // 클라이언트가 보낸 데이터를 읽어서 화면에 출력한다.
}
}catch(Exception e){
System.out.println(e);
}
}
void getMessage(){ // 소켓으로부터 메시지를 읽는다.
try{
while(true){ // 무한 루프
// 소켓의 입력 스트림으로부터 데이터를 한 라인을 읽어서 화면에 출력한다.
System.out.println("클라이언트: "+reader.readLine());
}
}catch(Exception e){
}finally{
System.out.println("클라이언트가 연결을 끊었습니다.");
try{
if(reader!=null) reader.close(); // 소켓의 입력 스트림을 닫는다.
if(socket!=null) socket.close(); // 소켓을 닫는다.
}catch(IOException ie){}
}
}
public static void main(String[] args){
Server2 server=new Server2();
server.startServer();
}
}
문자열 전송 클라이언트
클라이언트의 소켓은 서버와 연결하고 소켓의 출력 스트림으로 데이터를 송신한다. 코딩의 수고가 있기는 하지만 클라이언트 프로그램은 AWT로 제작해보자.
[그림 21-7] 서버(위)와 클라이언트(아래)의 실행화면
Client2.java
import java.awt.*;
import java.net.*;
import java.io.*;
import java.awt.event.*;
public class Client2 extends Frame{
private TextArea msgView=new TextArea(); // 메시지를 보여주는 텍스트영역
private TextField sendBox=new TextField(); // 문자열을 입력하는 텍스트필드
private PrintWriter writer; // 소켓의 출력 스트림
Socket socket; // 소켓
public Client2(String title){ // 생성자
super(title);
msgView.setEditable(false); // 텍스트영역을 사용자가 편집할 수 없도록 한다.
add(msgView,"North"); // 컴포넌트 배치
add(sendBox,"South");
// sendBox에 문자열을 입력하고 엔터를 누르면
// 문자열을 전송한다.
sendBox.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
// sendBox의 문자열을 출력 스트림으로 전송한다.
writer.println(sendBox.getText());
// msgView에 보낸 문자열을 추가한다.
msgView.append(sendBox.getText()+"\n");
// sendBox의 내용을 지운다.
sendBox.setText("");
}
});
pack(); // 프레임의 크기를 자동으로 맞춘다.
}
private void connect(){ // 서버와 연결하는 메소드
try{
msgView.append("서버와의 연결을 시도합니다.\n");
socket=new Socket("127.0.0.1", 7777);
msgView.append("연결되었습니다. 전송할 문자열을 입력하세요.\n");
// socket의 출력 스트림을 얻는다.
writer = new PrintWriter(socket.getOutputStream(), true);
}catch(Exception e){
msgView.append("연결 실패..");
}
}
public static void main(String[] args){
Client2 client=new Client2("서버로 데이터 보내기");
client.setVisible(true);
client.connect();
}
}
출처 : http://java.pukyung.co.kr/Lecture/Chapter21.php