이번 강좌 부터는 서버쪽의 네트웍을 위한 ServerSocket에 대해 공부하도록 합니다. 네트웍이 어려울 수도 있겠지만 부탁 드리고 싶은 것은 반드시 실습을 해보시라는 겁니다. 실습없는 이론은 없다고 보시면 됩니다. 자 그럼 시작 해 볼까요~
앞 강좌에서 배운 클라언트 소켓과 서버 소켓을 그림으로 구성하면 아래와 같습니다.
서버가 서버 소켓을 열고 소켓을 포트에 바이딩 한 후 클라이언트의 연결을 기다립니다.각 클라이언트의 연결을 서버 소켓이 쓰레드등을 이용 서버 소켓 객체를 만들어 클라이언트 연결 하나씩 전담하게 되는거죠.. 클라이언트 소켓과 서버 소켓의 연결과정은 잠시 후에 자세히 배우도록 하겠습니다.
ServerSocket Class
말 그대로 서버 소켓을 구현했으며 서버 소켓은 클라이언트의 연결을 기다리게 되는 겁니다. 서버 구현의 기본은 특정한 로컬 포트에 대해 ServerSocket 객체를 열고 클라이언트가 연결해 오기를 기다리는 것이며 클라이언트가 연결해 올때마다 ServerSocket 은 각각의 클 라이언트 연결에 대해 Socket 객체를 생성 합니다.ServerSocket 은 대개 InputStream 이나 OutputStream 을 통해 클라이언트와 데이터를 주고 받으며 이때 서버 소켓의 Port 번호는 1~65535 까지 사용 가능하며 이중 1~1023 까지 는 시스템 서비스 용으로 예약 되어 있습니다.
소켓 생성시 포트 번호를 0 으로 주는 것은 시스템에서 알아서 포트를 할당 하라는 의미 이며 ServerSocket 객체가 생성되자 마자 운영체제가 클라이 언트로 부터 연결을 받을 준비를 하게 되는 것입니다. 클라이언트가 시도한 연결은 Queue 에 들어가며 서버가 accept 메소드를 호출하면 하나씩 큐에서 빠져 나오게 되는 것 입니다. ServerSocket 생성시 몇 개의 연결을 Queue 에 넣을 것인 지 지정 할 수도 있습니다.
생성자는 다음과 같습니다.
– ServerSocket(int port)
• Creates a server socket on a specified port.
• The maximum queue length for incoming connection indications (a request to connect) is set to 50. If a connection indication arrives when the queue is full, the connection is refused.
– ServerSocket(int port, int backlog)
• Creates a server socket and binds it to the specified local port number, with the specified backlog.
• The maximum queue length for incoming connection indications (a request to connect) is set to the backlog parameter. If a connection indication arrives when the queue is full, the connection is refused.
이상 배운것을 이용하여 EchoClient와 EchoServer를 만들어 보도록 하겠습니다. 클라이언트에서 서버로 데이터를 보내면 서버가 메아리 처럼 다시 클라이언트에게 보내는 간단한 네트웍 예제 입니다. 결국 채팅 프로그램들도 다 이러한 기본 위에서 만드는 것이니 반드시 실습을 해 보시기 바랍니다.
[EchoServer.java] -- 실행시 서버소켓이므로 어느 포트로 소켓을 만들건지 포트 번호만 주면 됩니다. java EchoServer 5000
import java.io.*;
import java.net.*;
import java.net.*;
class EchoServer
{ public static void main( String[] args )
throws IOException
{
ServerSocket serverSock =
new ServerSocket( Integer.parseInt(args[0]) );
System.out.println(serverSock + ": 서버 소켓 생성");
while(true)
{
Socket sock = null;
try
{
sock = serverSock.accept(); //한순간에 accept 하나...
System.out.println(sock + ": 연결됨");
InputStream fromClient = sock.getInputStream();
OutputStream toClient = sock.getOutputStream();
byte[] buf = new byte[1024];
int count;
while( (count = fromClient.read(buf)) != -1 ) {
toClient.write( buf, 0, count );
System.out.write(buf, 0, count);
}
toClient.close();
System.out.println(sock + ": 연결 종료");
} catch( IOException ex )
{
System.out.println(sock + ": 연결 종료 (" + ex + ")");
} finally
{
try
{
if ( sock != null )
sock.close();
} catch( IOException ex ) {}
}
}
}
}
{ public static void main( String[] args )
throws IOException
{
ServerSocket serverSock =
new ServerSocket( Integer.parseInt(args[0]) );
System.out.println(serverSock + ": 서버 소켓 생성");
while(true)
{
Socket sock = null;
try
{
sock = serverSock.accept(); //한순간에 accept 하나...
System.out.println(sock + ": 연결됨");
InputStream fromClient = sock.getInputStream();
OutputStream toClient = sock.getOutputStream();
byte[] buf = new byte[1024];
int count;
while( (count = fromClient.read(buf)) != -1 ) {
toClient.write( buf, 0, count );
System.out.write(buf, 0, count);
}
toClient.close();
System.out.println(sock + ": 연결 종료");
} catch( IOException ex )
{
System.out.println(sock + ": 연결 종료 (" + ex + ")");
} finally
{
try
{
if ( sock != null )
sock.close();
} catch( IOException ex ) {}
}
}
}
}
[실행결과]
[EchoClient.java] //실행시 어느 서버의 어느 포트로 소켓을 연결 할건지를 매개변수로 줘야 합니다. java EchoClient Localhost 5000
import java.io.*;
import java.net.*;
import java.net.*;
class EchoClient
{ public static void main( String[] args )
throws IOException
{
Socket sock = null;
try
{
sock = new Socket(args[0], Integer.parseInt(args[1]));
System.out.println(sock + ": 연결됨");
OutputStream toServer = sock.getOutputStream();
InputStream fromServer = sock.getInputStream();
{ public static void main( String[] args )
throws IOException
{
Socket sock = null;
try
{
sock = new Socket(args[0], Integer.parseInt(args[1]));
System.out.println(sock + ": 연결됨");
OutputStream toServer = sock.getOutputStream();
InputStream fromServer = sock.getInputStream();
byte[] buf = new byte[1024];
int count;
while( (count = System.in.read(buf)) != -1 )
{
toServer.write( buf, 0, count );
count = fromServer.read( buf );
System.out.write( buf, 0, count );
}
toServer.close();
while((count = fromServer.read(buf)) != -1 )
System.out.write( buf, 0, count );
System.out.close();
System.out.println(sock + ": 연결 종료");
} catch( IOException ex )
int count;
while( (count = System.in.read(buf)) != -1 )
{
toServer.write( buf, 0, count );
count = fromServer.read( buf );
System.out.write( buf, 0, count );
}
toServer.close();
while((count = fromServer.read(buf)) != -1 )
System.out.write( buf, 0, count );
System.out.close();
System.out.println(sock + ": 연결 종료");
} catch( IOException ex )
{
System.out.println("연결 종료 (" + ex + ")");
} finally
{
try
{
if ( sock != null )
sock.close();
} catch( IOException ex ) {}
}
}
}
System.out.println("연결 종료 (" + ex + ")");
} finally
{
try
{
if ( sock != null )
sock.close();
} catch( IOException ex ) {}
}
}
}
오늘은 여기까지 하고 마감 하자구요~ 위에 예제인 경우 만약 클라이언트가 하나더 생겨 서버 소켓에 데이터를 보낼려면 어떻게 될까요? 문제가 있다면 이를 어떻게 해결 할 것인지 고민해 보시기 바라면서 다음 강좌에서 뵙도록 하겠습니다.
갑자기 기온이 뚝! 떨어 졌습니다. 감기 조심하세요~
댓글 없음:
댓글 쓰기