JAVA > LIBRARY > Java 소켓통신예제 Socket in TCP/IP protocol
 
JAVA
Library
Tip&Tech
Q&A
java공식사이트
Java  Platform Standard Edition 6 의 API 스펙
LIBRARY
  HOME > JAVA > LIBRARY
 
Java 소켓통신예제 Socket in TCP/IP protocol
작성일 : 10-02-04
조회 : 14,714  

Stream과 Socket

작성자: realmove / 작성일: 2000.5.4 / 대상: 자바 기초

 

차례

1. Stream

1) Stream 이란?

2) Stream 입력

3) Stream의 사용

2. Socket

1) Socket 이란?

2) Project1: 서버 / 클라이언트

서버
클라이언트
데이터 전송과 수신
예외상황 처리
Design & Coding
3) Project2: 계산기

Protocol의 정의
Class 설계 1: Client
Class 구현 1: Client
Class 설계 2: Server
Class 구현 2: Data 전송
Class 구현 3: Client monitoring
참고 예제
4) Project3: 채팅 프로그램

프로토콜 정의
서버 설계1: 소켓 준비와 Thread리스트 만들기
서버 설계2: 리스트를 이용하여 모든 thread에 메시지 전송하기
서버 설계3: ServerThread구현
클라이언트1: 소켓 연결, 메시지 전송
클라이언트2: 메시지 받기
참고 예제


--------------------------------------------------------------------------------

Stream for Data Transmision
1. 스트림이란?

stream

n.
1 개울(brook), 시내, 강(river).
a mountain stream 계류(溪流).
2 흐름, 수류, 분류(奔流); 해류; 기류; 광선. FLOW 類語
the Gulf Stream 멕시코 만류
a stream of tears 흐르는 눈물
down (up) [the] stream 하류(상류)에(로).
3 비유적 [때사상 따위의] 흐름, 경향, 형세(trend); 사조.
the stream of history 역사의 흐름
the stream of thought 사조.
4 연속되는 것, 끊임없이 이어지는 것(사람); 쇄도.
a stream of talk 그칠 줄 모르는 이야기.
5 컴퓨터 스트림 [데이터의 흐름].

dic.naver.com에서 찾아보니까 스트림이 이렇게 나오네요. 모든 컴퓨터 프로그램은 통신을 위해서 스트림을 사용합니다. 하나의 프로그램에서는 광역 변수를 사용하거나 함수에 인자를 전달하는 방식으로 어떤 값을 다른 함수로 전달할 수 있습니다. 하지만 서로 다른 두 개의 프로그램인 경우에는 어떨까요? 두 프로그램은 서로 어떤 함수가 있는지도 모를 뿐더러 상대편이 실행되고 있는지 또는 어떤 일을 하는지조차 알 수 없습니다. 그러한 상황에서 하나의 프로그램에서 다른 프로그램으로 어떤 값을 전달하기 위해서 스트림을 사용합니다.

 

만일 스트림에 대해서 알고 있는 사람이라면 바로 Socket으로 넘어가도 될 것 같네요.

스트림은 자바에서만 지원하는 것이 아니라 OS차원에서 지원을 하는 기능입니다. 이말은 스트림 통신을 하기 위한 두 프로그램이 반드시 자바로 작성될 필요는 없다는 것을 의미합니다. 하나는 자바로, 다른 하나는 C로 작성될 수도 있고, 다른 어떤 언어를 사용하는 것도 가능하다는 의미입니다.

사실 윈도우나 유닉스, 리눅스 등의 OS를 설치하여 컴퓨터를 사용하는 사람이라면 누구나 항상 스트림을 사용합니다. 예를 들어 윈도우의 도스창(command prompt) 또는 유닉스 콘솔에서 화면에 글자를 찍는 것이나, 프린터에 프린트를 하는 것이 그렇습니다. 우리는 간단하게 System.out.println("내용..."); 라는 명령으로 화면에 찍습니다. 그러나 실제로 println()메소드에서는 주어진 인자의 값을 적당한 장소에 스트림을 사용하여 쭉 보내주게 되죠. 스트림, 즉 하나의 연속적인 흐름으로 보내는 것입니다. 화면에 출력하기 위해서는 화면출력을 담당하는 위치에 스트림으로 보내면 되고, 프린터에 출력하고 싶다면 프린터출력을 담당하는 위치에 스트림으로 보내면 됩니다. 화일에 저장하는 것, 하니면 채팅프로그램처럼 두 프로그램이 통신을 하는 것, 모두 사실은 그런 메카니즘을 가지고 있습니다. 다음은 UNIX에서 파이프라인이라는 기능 속에서 스트림이 어떻게 사용되는지를 보여주는 예입니다.

 

UNIX를 사용해본 사람이라면 파이프라인을 알고 있을
 
것입니다. windows NT의 명령창에서도 지원하는 기능인데, ls는 도스에서 dir과 같은 기능을 하죠?
SHELL> ls | more
와 같이 같이 명령을 내리면 어떻게 될까요? 화일이 많은 경우 ls라고 그냥 하면 읽을 새도 없이 화면이 쭉 스크롤 되죠. 하지만 앞에서와 같이 하면 한 화면 만큼씩만 출력되게 됩니다. 실제로 이 작업은 두 개의 프로그램이 돌고 있는 것입니다. ls라는 프로그램과 more라는 프로그램이죠. 그냥 ls라고 쳤을 경우에는 결과를 화면출력을 담당하는 곳에 스트림으로 보내지만 지금처럼 파이프라인으로 연결하면, ls는 결과를 스트림으로 보내게 되고, 이것을 more호라는 프로그램에서 스트림으로 받아서 화면에 한 페이지씩 보여주게 되는 것입니다. 두 프로그램이 통신을 하는 경우 중의 대표적인 예가 바로 이러한 파이프라인이죠.
좀더 나아가면 파이프라인을 여러 개 사용할 수도 있습니다.
SHELL> ls | grep txt | more
짐작하다시피 이번에는 프로그램이 3개가 돌게 됩니다. ls가 화일의 명령을 뽑아서 스트림으로 보내면, 그것을 grep이라는 명령이 받아서 그중 txt라는 문자열을 포함하는 라인만을 골라서 다시 스트림으로 보냅니다. 마지막으로 more라는 프로그램이 앞에서와 같이 스트림으로 받아서 앞에서와 같이 한 화면씩 출력하게 됩니다.


 

2. 스트림 입력/ 스트림 출력


스트림에는 사실 여러 종류가 있습니다. byte스트림,문자열스트림,데이터그램스트림 등이 그것입니다. 여기서는 사실 문자열(String)스트림만을 다루려고 합니다. byte스트림과 문자열 스트림은 12라는 정수가 "12"로 가느냐(문자열스트림) 아니면 0C(12)인 숫자(byte스트림)으로 가느냐의 차이가 있을뿐 거의 비슷합니다. 데이터그램 스트림은 약간 다르지만 문자열 스트림을 알고나면 금방이해할 수 있을 것입니다.

앞의 UNIX의 파이프라인 예제를 보고 알아챈 사람도 있을테지만, 스트림은 입력과 출력이 있습니다. 즉 스트림을 보내는 것과 받는 것, 두 가지 동작이 있을 수 있다는 이야기입니다. 프린터에 출력하는 경우, 프로그램에서는 프린터스트림에 보내는(출력) 역할을 할 것이고, 프린터는 그것을 스트림에서 받아서(입력) 인쇄하게 되겠죠. 앞의 파이프라인의 경우, 앞에 있는 프로그램에서 스트림으로 출력을 하면, 뒤에 있는 프로그램에서 그것을 받게 되는 것입니다.


 


3. Stream의 사용


C와 같은 다른 언어와 마찬가지로 자바에서도 InputStream과 OutputStream을 지원하고 있습니다. 즉 이 클래스들을 입력 또는 출력하고자하는 적당한 객체에 연결시켜준 다음 read나 write 메소드 등을 사용하여 입력과 출력을 하게 되는 것입니다. 만일 키보드로부터 입력을 받아서 화면에 출력하고자하면,

 

InputStream in=System.in;
OutputStream out=System.out;

와 같이 선언하여, in.read()문으로 내용을 입력 받아서 out.write()메소드를 사용하여 출력할 수 있다는 말입니다. 만약 in과 out이 각각 화일이나, 프린터 등에 연결되어 있다면 물론 화일에서 내용을 읽거나 쓸 수 있고, 프린터에 출력할 수도 있습니다.

하지만 여기에서는 스트림을 사용하는 일반적인 방법에 대해서는 설명하지 않고, 바로 소켓으로 넘어가도록 하겠습니다. 자바에서는 화면에 출력하기 위해서 콘솔(화면)을 사용하는 경우는 거의 없습니다. 하지만 콘솔(키보드)에서 입력받기 위한 경우나, 프린터에 출력하고자하는 경우, 화일의 내용을 읽거나 쓰는 경우에는 반드시 스트림을 사용합니다. 또한 바로 뒤에서 다룰, TCP/IP Protocol을 이용한 인터넷에서의 통신에서도 물론 스트림을 사용합니다.

 

--------------------------------------------------------------------------------

 


Socket in TCP/IP protocol

1. Socket


여기서부터가 이번 글에서의 본론입니다. 사실 swing이나 awt같은 추상윈도우툴킷을 사용하면 키보드로부터 입력받는 것을 직접 작성할 필요도 없고, 프린터 출력 부분도 사실 남이 작성해 놓은 코드를 복사해서 약간 수정하면 쉽게 할 수 있습니다. 화일 입출력도 스트림을 제대로 설정만 해놓으면 화면에 출력하듯이 간단하게 입력과 출력을 사용할 수 있습니다. 하지만 socket을 이용한 프로그램만은 그렇지가 않습니다. 물론 개념은 스트림을 사용하는 다른 작업들과 크게 다르지 않지만 기술적인 면에 있어서 원하는 기능을 구현하는 것이 그리 쉽지만은 않기 때문입니다.

이제부터 정신을 똑바로 차리세요. 이글에서는 소켓의 구조나 TCP/IP와 같은 일반적인 네트워크 정보에 대해서는 생략하도록 하겠습니다. 미리 알고 있어야 한다는 얘기는 아니고 자세히는 몰라도 된다는 말입니다. 이글에서는 먼저 소켓을 정의해서 스트림을 사용하여 입력과 출력을 받는 것을 간단히 구현하는 프로젝트를 진행해보고, 마지막에 가서는 하나의 서버에 여러 개의 클라이언트가 접속하는 멀티 클라이언트 채팅프로그램을 작성하는 프로젝트를 진행하도록 하겠습니다.

 

 

프로젝트1. 서버와 클라이언트


여기서 완성될 프로그램은 다음과 같은 순서로 작동을 하게 됩니다.

 

1. 서버가 소켓을 생성하고 연결을 기다린다.
2. 클라이언트에서 서버의 소켓에 연결한다.
3. 클라이언트에서 데이터를 전송다.
4. 서버에서 데이터를 받아서 화면에 출력한다.
5. 서버와 클라이언트의 소켓 연결을 끊는다.

이 프로젝트에서는 물론 두 개의 프로그램을 작성해야 하겠죠. 서버 쪽과 클라이언트 쪽입니다.

각각 SocketServer.java 와 SocketClient.java 로 하기로 하죠.

 

예제 프로그램: SocketServer.java / SocketClient.java
우선은 위의 예제 프로그램을 다운받아서 실행시켜보기를 바랍니다. 콘솔(윈도우에서는 명령 프롬프트 = 한글 MS-DOS)를 두 개를 띄워야겠죠. 아무 콘솔에서나 두 프로그램을 컴파일 합니다.

SHELL> javac SocketServer.java
SHELL> javac SocketClient.java

컴파일 된 후 실행시킵니다. 하나의 콘솔에서 서버를 먼저 실행시킵니다. 파라미터로 포트값을 주는데, 주지 않으면 5777번이 잡히게 됩니다. 포트번호는 3000번 이상의 값을 주는게 좋습니다.

SHELL> java SocketServer 6000

그러면 포트번호와 클라이언트의 연결을 기다린다는 메시지가 나오게 됩니다. 6000은 포트 번호입니다. 이 값은 생략가능하고 생략하면 5777번 포트를 사용하게 됩니다. 그러면 클라이언트를 실행시킵니다. 파라미터는 IP와 포트번호를 줍니다.

SHELL> java SocketClient 6000 211.35.136.174

포트번호는 물론 앞의 서버에서 설정한 포트번호와 같아야 하겠죠. IP는 자신의 컴퓨터 아이피를 주면 됩니다. IP를 주지 않으면 127.0.0.1에 연결하는데, 보통 이 번호는 로컬 호스트, 즉 자기 자신을 의미합니다. 만약 이 번호로 되지 않거나 다른 컴퓨터에서 SocketServer를 실행시켰다면 IP를 반드시 써주어야 하겠죠. 아무튼 서버와 포트 번호가 일치하고 IP를 적당히 주었다면 클라이언트는 서버에 연결하여 열글자의 데이터를 보낸 후 종료하게 됩니다. 서버도 소켓을 끊고 종료하게 됩니다.
 


위의 예제를 실행시켜보았다면, 아직 소스는 보지 말고 공부를 시작해봅시다. 소켓은 TCP프로토콜을 사용하여 통신을 하는데 쓰인다고 앞에서 얘기했습니다. 따라서 소켓의 기본은 IP와 port겠죠. 이것들이 각각 무엇을 의미하는지는 알지 못해도 상관없습니다. 아무튼 IP는 컴퓨터마다 가진 고유한 주소이고, port는 통신을 위한 연결 라인과 같은 것이라고만 알고 있으면 됩니다. 아무튼 소켓을 사용하여 어떤 프로그램과 연결을 하기 위해서는 그 프로그램이 있는 컴퓨터의 IP와 소켓을 만든 port번호를 알고 있어야 한다는 것만 기억하면 됩니다.

 

1) 서버 소켓 준비하기( SocketServer.java )

통신을 하기 위해서는 먼저 서버에서 소켓을 준비해야 합니다. 자바에서는 그것을 위해 ServerSocket이라는 클래스가 제공됩니다. 다음과 같이 초기화를 하면 서버 소켓이 만들어집니다.

이것은 java.net 패키지에 들어있습니다.

 

ServerSocket 소켓변수이름=new ServerSocket(포트번호);

 

포트번호는 정수이고, 소켓변수이름은 아무것이나 변수로 쓸 수 있는 것을 써주면 됩니다. 예를 들면 ServerSocket srvSocket=new ServerSocket(5777); 라고 선언할 수 있겠죠.


다음은 이 서버소켓을 사용하여 클라이언트와 통신할 다른 소켓을 만들어주는 작업입니다. 서버 쪽에서는 반드시 두 개의 소켓이 필요합니다. 하나는 서버용 소켓인데 이것으로는 통신을 할 수가 없고 단지 클라이언트의 연결을 기다립니다. 따라서 클라이언트와 연결이 되면 실제로 통신을 하기 위해서는 소켓을 하나 더 만들어서 연결해주어야 한다는 것을 의미한다.

이 소켓은 서버소켓.accept()명령으로 만들어줄 수 있습니다.

 

Socket soc=srvSocket.accept();

 

여기서 srvSocket은 아까 선언해준 서버소켓의 이름이 됩니다. 클래스의 이름이 Socket임을 눈여겨 보아야 합니다. 클라이언트에서도 이 소켓을 사용하여 연결하게 됩니다.

다음은 입력을 위한 스트림을 선언하는 부분입니다. 물론 만들어 놓은 소켓에서 스트림을 얻어와야 하겠죠. 스트림은 java.io 패키지에 포함되어 있습니다.

 

InputStream is=soc.getInputStream();

 

이렇게 is는 스트림변수 이름이고, soc는 앞에서 선언한 소켓의 이름입니다. 이렇게 되면 입력스트림이 얻어졌습니다. 그리고나서, 이 스트림에서 입력을 받기위해서는 이 스트림을 읽을 수 있는 Reader를 정의해야만 읽을 수가 있겠죠. 마치 비디오테이프와 VTR과 같은 관계입니다. VTR에 비디오 테이프를 넣어주어야 하겠죠.

 

InputStreamReader isr=new InputStreamReader(is);

 

여기서 is는 앞에서 선언한 inputstream이고, isr은 InputStreamReader의 이름입니다. 이것으로 서버쪽에서 소켓을 준비하는 것은 모두 끝났습니다. 데이터를 읽기 위해서는 InputStreamReader에 있는 read()메소드를 사용하면 됩니다.

즉, int a=isr.read();와 같이 하면 a에 한 글자가 입력됩니다. int값으로 넘어오는데, 문자로 바꾸기 위해서는 형변환(type casting)을 해주면 되겠죠.

char a=(char) isr.read(); 와 같이 하면 되겠죠.

들어오는 문자들을 하나의 문자열에 저장하기 위해서는 str=str+(char)isr.read(); 와 같이 문자열에 더해주면 됩니다.

 

2) 클라이언트 소켓 (SocketClient.java)

클라이언트 소켓은 서버 소켓보다 훨씬 쉽습니다. 서버 소켓은 필요가 없고, InputStream을 OutputStream으로, InputStreamReader를 OutputStreamWriter로 바꾸기만 하면 됩니다.

먼저 소켓을 만들어야겠죠. 앞에서 생성한 서버의 IP와 port번호를 알고 있어야 합니다.

 

Socket soc=new Socket("127.0.0.1", 5777);

 

여기서 "127.0.0.1"은 IP주소입니다. 앞에서 설명한대로 이것은 자기 자신을 의미합니다. 만약 서버가 다른 컴퓨터에 있다면 그 컴퓨터의 IP를 적어야 합니다. 5777은 포트번호입니다. soc는 물론 소켓의 이름으로 변수로 쓸 수 있는 것을 적어주면 됩니다. 여기서 아까 눈여겨봐야 한다던 것을 기억해서 Socket과 동일한 클래스를 사용하고 있다는 것을 확인하세요.

다음은 이 소켓에서 스트림을 생성하는 것입니다. 서버로 데이터를 보내는 것이니까 당연히 InputStream이 아니라 OutputStream을 사용해야 하겠죠.

 

OutputStream os=soc.getOutputStream();

 

이 문장이 잘 이해가 안가면 앞의 서버 쪽의 InputStream을 만드는 부분을 읽어보세요. 이제 앞에서와 마찬가지로 OutputStreamWriter를 만들어줘야 하겠죠.

 

OutputStreamWriter osw=new OutputStreamWriter(os);

 

이렇게 하면 writer까지 무사히 만들어졌습니다. 이제 데이터를 전송하기 위해서는 write()메소드를 사용하면 됩니다. 구체적으로 어떻게 사용하는지는 다음에서 배우기로 합시다.

 

3) 스트림을 통한 데이터의 입출력

앞에서 InputStreamReader와 OutputStreamReader를 만들었습니다. 이제 그 클래스에 구현된 메소드(read, write)를 사용해서 그냥 읽고 쓰면 됩니다.

자바 스펙 에서 InputStreamReader와 OutputStreamReader를 찾아 보세요.

찾기가 쉽지는 않겠지만, 앞으로 자바 공부를 하기 위해서는 하루에도 수십번 씩 해야 하는 일이니까 스스로 찾아보세요.

 

InputStreamReader에 보니까 read 메소드가 두 개로 정의되어 있네요.

- int read();
- void read(char[] chr, int offset, int length);

앞의 것은 설명에 한 글자를 얻어온다고 적혀있네요. 즉, a=isr.read();라고 하면 a에는 한 글자만 들어가 있다는 뜻입니다. a는 정수형(int)이어야 합니다. 이것을 문자로 바꾸기 위해서는 형변환(type casting)을 해주어야 합니다. 뒤의 것은 몇 번째 글자(offset)부터 몇 글자(length)를 얻어와서 char의 배열에 넣는다는 의미인 것 같습니다.

 

public static void main(String args[]) {
   InputStreamReader isr=new InputStreamReader(new ServerSocket(5777).accept().getInputStream());
   String str="";
   for (int i=0; i<10; i++) {

     str="str+(char)isr.read();"

   }

   System.out.println(str);

   isr.close();

}


자 프로그램이 하나 완성되었습니다. InputStreamReader를 만들기 위해 ServerSocket을 만들고 그것의 accept()메소드를 이용해서 Socket을 만들고 다시 InputStream을 만드는 모든 과정을 그냥 한 줄로 끝냈습니다. 괄호의 가장 안쪽부터 차근차근 읽어보면 앞에서 설명한 순서로 만들어주었다는 것을 알 수 있습니다. 다음에는 str을 String으로 선언해주고 for문으로 열개의 문자를 읽어와서 str에 더해주고서 다시 str을 출력하는 프로그램이네요.
주의해야 할 점은 이 코드는 실행되지 않는다는 점입니다. 바로 다음에서 할 exception처리를 보고나면 이 코드를 수정하여 실행시킬 수 있습니다. 적당한 패키지(java.io, java.net)를 import하고, exception을 처리해서, 이 클래스를 SocketServer.java 클래스에 넣어주면 서버는 완성됩니다.

클라이언트부분은 좀더 쉽습니다.


public static void main(String args[]) {

   OutputStreamWriter osw=new 
   OutputStreamWriter(new Socket("127.0.0.1",5777).getOutputStream());
   String str="0123456789";
   osw.write(str,0,10);
   osw.flush();
   osw.close();
}

아까와 마찬가지로 spec에서 찾아보면 OutputStreamWriter클래스에는 write()가 여러 개로 정의되어 있습니다. 한 글자씩 전송하는 것도 있고, 지금처럼 사용할 수도 있습니다. 지금은 str의 0번째 글자부터 10개의 글자를 전송하라는 의미입니다. osw.flush();는 글자를 실제로 전송하라는 의미입니다. 이것을 써주지 않으면 메시지를 받는 쪽에서 실제로 읽을 수가 없습니다.

방금 해보니까, 위의 코드들은 전부 실행이 되네요. 물론 exception처리를 해줘야 합니다. 그럼 시간 낭비하지 말고 어서 exception처리를 배워봅시다.

 

4) exception처리

exception은 단어 뜻 그대로 예외상황을 의미합니다. 만약 서버에서 서버소켓을 만드는데 사용하고자하는 포트(예를 들면 5777)가 사용중이라고 해봅시다. 그러면 소켓을 만들 수가 없겠죠. 하지만 이것은 컴파일할때는 에러가 나지 않습니다. 컴파일할때 포트를 사용하는지를 검사해보는 것은 의미가 없겠죠? 컴파일할때는 포트가 사용중이 아니더라도 실행할때 사용중일 수도 있으니까요. 클라이언트에서 소켓을 만들때도 마찬가지입니다. 만약 서버를 실행시키지 않은 상황이라면, 클라이언트를 아무리 잘 작성해서 실행시키더라도 소켓을 연결할 수가 없겠죠. 이러한 상황을 예외상황(exception)이라고 합니다. 예외상황은 오류(error)와는 전혀 다른 것입니다. 에러는 사용자가 코딩할때 실수해서 컴파일조차 안되는 상황이지만, 예외상황은 코딩은 잘되었더라도 시스템의 상황에 따라서 발생하는 것입니다. 예컨대, 에러는 컴파일할때, 예외상황은 실행할때 발생한다는 것입니다.

 

예외상황을 잘 잡아주는 것은 대단히 중요합니다. 지금처럼 서버 소켓을 만들었을때 예외상황이 발생하여 시스템의 자원(메모리, CPU사용 등)을 반환하지 않는다면 컴퓨터를 재부팅하기 전에는 계속해서 시스템의 자원을 잡아먹기 때문에 시스템을 느려지게하는 원인이 될 수 있죠. 자바에서는 물론 그런 일이 발생하지 않습니다. 자바 버추얼 머신(java.exe)을 통해서 실행이 되기 때문에 java.exe가 실행을 중지하면 모든 자원은 자동으로 반환되기 때문입니다. 하지만 C와 같은 프로그램에서는 예외상황에서 적절히 자원을 반환해주지않으면 앞에서 설명한 일이 발생하게 됩니다.

아무튼 예외 상황을 잡아주는 것은 프로그램의 신뢰성을 높이는데에 매우 중요합니다. 소켓을 만들 수 없을때는 최소한 소켓을 만들 수 없다는 메시지 정도는 출력해주는게 프로그래머의 당연한 의무겠죠. 이 소켓 프로그램(SocketServer.java Socket Client.java)에서 예외상황을 발생시킬 수 있는 메소드는 크게 두 가지가 있습니다. 첫째는, 1.소켓을 만들때, 앞에서 소켓을 만들 수 없다는 예외상황이 발생할 수 있습니다. 둘째는, 2.데이터를 입력받거나 출력할때 중간에 소켓이 끊겼거나 하는 상황에서 발생할 수 있습니다. 따라서 SocketServer.java / SocketClient.java에서는 각각 최소한 두 가지 씩의 예외처리를 해주어야 하겠죠.

예외상황의 처리는 try 와 catch문으로 처리할 수 있습니다. finally이라는 예약어도 있지만 이것은 여기서 생략하기로 하죠. 사용 방법은 C에서와 완전히 동일합니다. 예외상황이 발생할 수 있는 메소드를 try { }로 감싸고서 예외상황은 catch에서 잡아서 처리하는 것입니다. 직접 코드를 만들어 봅시다.


public static void main(String args[]) {
   try {
      // 아까 그 내용들....
   } catch (IOException e) {
      System.out.println("Exception이 발생했습니다.");
   }
}

이렇게 하면 됩니다. IOException은 여러 가지 예외상황중 IO(Input/Output)에 관계된 예외상황을 잡아내라는 의미입니다. 스트림이니까 예외상황은 IO에 관계된 것이겠죠. 이러면 실행을 주-욱 하다가 뭔가 예외상황이 발생하면 catch다음에 있는 문장을 실행하고 넘어간다는 의미입니다. 여기서는 "Exception이 발생했습니다."라는 메시지를 출력하겠죠.

 

물론 이렇게 하면 잘 돌아가지만 이상적인 예외처리라고는 할 수 없습니다. 왜냐면 예외상황을 발생할 수 있는 부분은 두 부분인데, 그냥 전체적으로 try catch로 묶어버려서 어느 곳에서 예외상황이 발생되더라도 그냥 "Exc.."라는 메시지만 출력하고 끝내버려서, 사용자는 도대체 어느 부분에서 예외상황이 발생했는지를 알 수 없다는 점입니다. 이렇게 되면 프로그래머는 코드 중 어디가 틀렸는지 알 수 없고, 또는 사용자는 자신이 뭘 잘못했는지를 알 수가 없겠죠. 따라서 가장 이상적인 방법은 try - catch를 예외를 발생할 수 있는 부분들에서 각각 써주어야 한다는 것입니다. 이렇게 하면 어떤 부분에서 예외 상황이 발생했는지를 알 수 있기 때문입니다.

 

//SocketClient.java
import java.io.*;    // Stream, Reader, Writer를 사용하기 위해
import java.net.*;   // Socket을 사용하기 위해
 
public class SocketClient {
 
  public static void main(String args[]) {
 
    OutputStreamWriter osw=null;
 
    try {
      osw=new OutputStreamWriter(new Socket("127.0.0.1",5777).getOutputStream());
    } catch (IOException e) {
      System.out.println("소켓을 만드는 데에 실패했습니다.");
      System.exit(-1);
    }

    String str="0123456789";

    try {
      osw.write(str,0,10);
      osw.flush();
    } catch (IOException e) {
      System.out.println("데이터 전송에 실패했습니다.");
    } 

    try {
      osw.close();
    } catch (IOException e) {
      System.out.println("소켓을 닫는데 실패했습니다.");
    }
  }
}

이제는 완전한 프로그램이 작성되었습니다. 막상 코딩해보니 예외상황(exception)이 두 부분이 아니라 세 부분에서 발생할 수 있군요. 소켓을 닫는 부분도 생각을 해야 하겠죠. 첫번째 예외처리에서 System.exit(-1);은 프로그램을 종료하라는 의미입니다. 소켓이 생성되지 않았다면 뒤에 있는 데이터를 전송하는 부분이나 소켓을 닫는 부분이 전부 의미가 없는 일이 되겠죠. 따라서 소켓이 생성되지 않았다면 프로그램을 종료하는 것이 좋겠죠.

서버쪽은 각자가 작성해 볼 수 있을 것입니다. 클래스를 만들어서 적당한 패키지를 import하고 예외처리만 해주면 서버도 잘 작동될 수 있을 것입니다.

그리고나서 여러 가지 상황을 체크해보세요.

 - 서버를 돌리지 않는 상황에서 클라이언트만 실행해보기도 하고,
 - 서버를 하나 돌리고, 똑같은 포트를 사용하는 서버를 한 번 더 실행해보세요.

 

5) 진짜로 만들어보기

앞에서 드디어 완전히 동작하는 소켓 프로그램을 작성하였습니다. 서로 완전히 독립적인 두 프로그램이 서로 통신을 하는 것이 대단히 신기하죠? 사실 프로그래밍에서 제일 재미있는 부분은 윈도우 프로그래밍(swing, awt)하고 소켓 프로그래밍인 것 같습니다. 하지만 이렇게 만들면 사실 동작은 하겠지만, 객체지향언어인 자바 프로그램이라고 말하기 힘들겠죠.

왜냐면 일단 클래스를 사용하지 않았습니다. 클래스는 사실 main메소드를 사용하려고 그냥 써준 것 뿐이지, 만들어놓은 클래스를 어디에서도 사용하지 않아서, 사실 C프로그램과 별로 달라 보이지 않습니다. 그래도 객체지향언어인데 자존심이 있지...

클래스를 제대로 구현하지 못한 이 프로그램은 클래스의 장점들을 사용할 수 없음을 의미합니다. 다른 클래스에서 사용하는 것은 완전히 불가능합니다.

그럼 과제로 생각하고, 제대로된 객체지향 방식에 의해 프로그래밍을 해보세요. 그 한 예가 처음에 제시했던 SocketServer.java / SocketClient.java가 될 수 있을 것입니다. 한 번 해보다가 잘 안되면 제가 작성한 프로그램을 참고해서 반드시 직접 코딩해보세요.

[출처] Java 소켓통신예제|작성자 뮤즈


 
 

Total 22
번호 제   목 조회
22 Java SE 6 한글 API 문서입니다. 4130
21 Stream for Data Transmision 2559
20 setAutoCommit(false) 에 대해서... 7732
19 java.net 패키지 - Url 클래스 5487
18 소켓 연결 샘플 4883
17 Java 소켓통신예제 계산기 채팅프로그램 6743
16 Java 소켓통신예제 계산기 프로그램 5115
15 Java 소켓통신예제 Socket in TCP/IP protocol 14715
14 Java 소켓통신예제 13314
13 자바 컴파일과 실행 에 사용되어지는 javac, java 명령어의 옵션 6042
12 자바 api 메뉴얼 3997
11 java.util 패키지 5303
10 J2SE, J2EE, J2ME 3848
9 이클립스 사용방법 9382
8 리눅스 자바설치 4097
7 IBM 이클립스의 기본적인 사용법을 설명 4606
6 자바언어의 특징 4229
5 자바 API 문서에서 substring 메서드의 사용방법 입니다. 11146
4 JAVA MySQL 연동하기 9265
3 JAVA 데이터 베이스 드라이버 명칭과 데이터베이스 URL 3809
 1  2  
 
개인홈페이지 덤벙닷컴은 프로그래머와 디자이너위한 IT커뮤니티 공간입니다.
Copyright ⓒ www.dumbung.com. All rights reserved.