1996년 3월 19일 첫 출판


앞 페이지 뒷 페이지 색인


자바 네트워크 프로그래밍

가멜론 사이트에 가면 채팅 애플릿이 있다. 별다른 채팅 프로토콜을 사용하지 않고도 바로 HTML 문서 내에 자바 애플릿이 실행되어 채팅에 참여할 수 있다. 기존의 irc 서버와 CGI 함수를 이용하여 별도의 채 팅 창을 열어야 했던 불편이 이제 자바를 지원하는 웹 브라우저에서는 완전히 해결된 셈이다.
[그림] 가멜론 사이트의 채팅 
애플릿

 그럼 이제 자바 네트워크 프로그래밍의 세계로 들어가 보자. 자바는 서버-클라이언트 모델의 분산 환경을 기본으로 지원하는데 이는 버클리 소켓 라이브러리(win32에서는 winsock 라이브러리)를 포함하고 있기 때문이다.
[그림] java.net 패키지 클래스 계층 구조
<그림 > java.net 패키지 클래스 계층 구조

자바 네트워크 프로그래밍은 크게 두 가지 방향이 있다. 하나는 Socket 혹은 ServerSocket 클래스를 이용하여 클라이언트/서버 소켓 프로그래밍을 하는 것이고 다른 하나는 URL 클래스를 이용하여 보다 쉽게 인터넷에 연결되어 있는 네트워크를 접속하고 정 보를 받는 것이다.

URL 클래스

URL(Uniform Resource Locator)은 인터넷의 특정 자원에 대한 주소를 나타내는 말로 인터넷 혹은 월드와이드웹의 관문이라 할 수 있다. URL의 구성 요소는 크게 프로토콜과 자원이 위치하고 있는 주소, 두 부분으로 나누어진다. 아래의 예제 프로그램에서 "http"는 프로토콜에 해당하고 "orange.hnc.net/~yoonforh"는 주소에 해당한다.
다음의 예제는 지정된 URL로부터 문서를 받아서 표준 출력으로 출력하는 프로그램이다. 스트림 입력 부분을 앞의 TextCopy 예제 소스와 비교해 보길 바란다. TextCopy 예제의 경우에는 FileInputStream 클래스 인스턴스를 생성하여 그로부터 DataInputStream 인스턴스를 생성하였고 아래의 URLTest의 경우에는 URL 클래스의 openStream() 도구를 사용하여 바로 DataInputStream 인스턴스 를 생성하는 차이 이외에는 동일하게 스트림으로 다룰 수 있다.

URLTest.java

 
URL 클래스의 주요 도구는 다음과 같다.

1) public int getPort() : 포트 번호를 구한다. 포트가 지정되어 있지 않으면 -1을 돌려준다.
2) public String getProtocol() : 프로토콜을 구한다.
3) public String getHost() : 호스트 이름을 구한다.
4) public String getFile() : 파일 이름을 구한다.
5) public String gerRef() : HTML 문서 내부의 위치를 지정하는 <a name="..."> 태그의 값을 구한다.
위 예제의 결과는 다음과 같다.

실행 결과

 
Ref는 '#dir'에서 지정한 값인 dir로 출력됨을 볼 수 있다. 마찬가지로 Port 번호의 경우 예제처럼 ':80'을 지정하지 않으면 -1 값이 구해진다. 보통 웹 브라우저는 http 프로토콜의 경우 포트 번호가 지정되지 않으면 80으로 간주한다.

6) public boolean equals(Object obj) : 두 URL을 비교한다.
7) public boolean sameFile(URL other) : ref 값을 제외하고 동일한 파일을 가르키는지 비교한다.
8) public String toString() : URL을 보통 사용하는 스트링으로 바꾸어준다.
9) public URLConnection openConnection() throws IOException : URL이 가리키는 원격 객체에 대한 접속을 포함하는 URLConnec tion 객체를 생성한다. 적합한 프로토콜 핸들러를 실행하게 된다.
10) public final InputStream openStream() throws IOException : 예제에서처럼 입력 스트림을 연다.
11) public final Object getContent() throws IOException : 열려 있는 연결에서 내용을 가지고 온다.

소켓 프로그래밍

네트워크 프로그래밍에 가장 많이 사용되는 소켓에는 두 가지 종류가 있음은 모두 잘 알고 있을 것이다. 소켓은 사용하는 전송 프로토콜에 따라 Transmission Control Protocol(TCP)를 이용하는 스트림 소켓과 User Datagram Protocol(UDP)를 이용하는 데이 터그램 소켓, 두 가지로 나눌 수 있다. 스트림 소켓을 대표하는 자바 클래스는 클라이언트 소켓을 생성하는 java.net.Socket 클 래스와 서버 소켓을 생성하는 java.net.ServerSocket 클래스이며 데이터그램 소켓을 대표하는 자바 클래스는 java.net.DatagramS ocket 클래스이다.
먼저 클라이언트 소켓 클래스인 Socket 클래스와 이에 대응되는 서버 소켓 클래스인 ServerSocket 클래스를 알아 보자.
Socket 클래스와 ServerSocket 클래스는 보통은 소켓 실행 클래스인 SocketImpl 추상 클래스를 이용하여 세부적인 소켓 작업, 즉 create(), bind(), listen(), connect(), accept(), close() 등을 수행한다. SocketImpl 클래스 인스턴스는 SocketImplFactor y 인터페이스의 createSocketImpl() 도구를 사용하여 생성한다. 이렇게 SocketImpl 클래스 인스턴스를 만드는 이유는 사용되는 파이어월의 종류에 따라 소켓 실행을 바꿀 수 있도록 하려는 것이다.
Socket 클래스의 생성자(Constructor)와 주요 도구를 살펴 보자.

1) public Socket(String host, int port) throws UnknownHostException, IOException : 스트림 소켓을 하나 생성하여 지정된 호스트의 지정된 포트에 연결한다.
2) public Socket(String host, int port, boolean stream) throws IOException : 세 번째 인자가 true이면 스트림 소켓을, fal se이면 데이터그램 소켓을 생성하여 지정된 호스트의 지정된 포트에 연결한다.
3) public Socket(InetAddress address, int port) throws IOException : 스트림 소켓을 하나 생성하여 지정된 주소의 지정된 포트에 연결한다.
4) public Socket(InetAddress address, int port, boolean stream) throws IOException : 세 번째 인자가 true이면 스트림 소 켓을, false이면 데이터그램 소켓을 생성하여 지정된 주소의 지정된 포트에 연결한다.

5) public InetAddress getInetAddress() : 소켓이 연결될 인터넷 주소를 돌려준다.
6) public int getPort() : 소켓이 연결될 상대방 포트를 구한다.
7) public int getLocalPort() : 소켓이 연결될 지역 포트를 구한다.
8) public InputStream getInputStream() throws IOException : 소켓에 대한 입력 스트림을 구한다.
9) public OutputStream getOutputStream() throws IOException : 소켓에 대한 출력 스트림을 구한다.
10) public synchronized void close() throws IOException : 소켓을 닫는다.
11) public String toString() : 소켓의 주소와 포트를 스트링으로 만들어준다.
12) public static synchronized void setSocketImplFactory(SocketImplFactory fac) throws IOException : 클라이언트의 Socke tImplFactory를 지정한다. 한 번만 지정 가능하다.

이에 대응되는 ServerSocket 클래스의 도구는 소켓의 도구와 거의 동일하지만 accept()가 있고 getPort()와 스트림 관련 도구들 이 없는 점이 다르다.
ServerSocket의 생성자는 다음과 같다.

1) public ServerSocket(int port) throws IOException : 지정된 포트에 서버 소켓을 생성한다.
2) public ServerSocket(int port, int count) throws IOException : 서버 소켓을 생성하여 지정된 지역 포트에 bind한 후 list en한다. 포트 값을 0으로 지정하면 임의의 포트를 시스템이 지정한다. count 값은 서버 소켓이 listen할 최대 시간이다.

서버/클라이언트 모델을 간단하게 구현한 예제를 살펴 보자. 다음 예제는 인터넷에서 공개된 것에 필자가 주석을 첨가한 것이다 .
소스를 살펴보기 전에 먼저 여기에서 사용된 java.util.Vector 클래스에 대해서 알아 보자.
이 벡터 클래스는 크기 변경이 가능한 객체 배열이라고 볼 수 있다. 벡터 클래스는 지정된 크기와 크기 증가치를 사용하여 저장 용량을 최적화한다. 벡터의 크기는 최소한 초기에 지정된 벡터의 크기이고, 초기치에다가 크기 증가치의 배수를 더한 값이다. 많은 객체들을 벡터에 넣기 전에 앞서, 크기를 지정하면 재할당을 여러 번 수행하는 부하를 줄일 수 있다.

서버 : GenericServer.java

 
서버에서 주의해서 볼 부분 중 하나는 연결된 소켓에서는 입력 혹은 출력 스트림을 바로 얻어서 (getInput Stream(), getOutputStream()) 쉽게 메시지를 주고 받을 수 있다는 점이다. 연결된 소켓은 서버이든, 클라이언트이든 Socket 클 래스 인스턴스를 사용한다. 이 연결 Socket 클래스 인스턴스는 서버에서는 accept()의 반환값으로 구하고, 클라이언트에서는 서 버의 주소와 포트를 지정한 Socket 생성자에서 바로 구한다.

클라이언트 : Client.java

 

클라이언트 소켓은 다중 쓰레드 기법을 사용할 필요가 없으므로 무척이나 간단하다. Socket() 생성자가 C 언어의 socket(), connect() 함수 등을 동시에 수행하므로 코드도 훨씬 간단해지고, 스트림 클래스를 이용한 입출력 관리는 더욱 코드를 분명하고 간 단하게 해준다. 과제를 하나 낸다면, 직접 에코 서버(스트림 소켓, 포트 7)에 접속하는 에코 클라이언트를 만들어 보자. 30줄도 채 안되는 아주 간단한 에코 테스트 예제 하나가 자바 사이트에 공개되어 있으니 비교해보길 바란다. 


앞 페이지 뒷 페이지 색인