본문 바로가기

JAVA/네트워크 프로그래밍

[JAVA] 소켓으로 서버에 쓰기(Server)

대부분의 프로토콜이 서버에게 읽기와 쓰기를 모두 요구하기 때문에, 이를 구현할 줄 알아야 한다.


이전과 동일하게 연결을 받아들이지만, 이번에는 InputStream과 OutputStream을 모두 요청한다.


InputStream을 이용하여 클라이언트가 보내는 내용을 읽고, OutputStream을 사용하여 클라이언트에게 쓴다.


이 과정에서 중요한 점은 프로토콜을 잘 이해하고, 읽어야 할 때와 써야 할 때를 잘 구분하는 것이다.




RFC 862에 정의된 에코프로토콜은 서버와 클라이언트가 데이터를 주고 받는 가장 간단한 서비스 중의 하나이다.


클라이언트는 에코 서버의 포트 7번에 대해 소켓을 열고 데이터를 보낸다. 그리고 서버는 받은 데이터를 다시 돌려보낸다.


에코 프로토콜은 라우터나 방화벽의 오동작으로 인해 데이터가 손실되지 않았는지, 네트워크를 확인 하는 데 유용하게 사용된다.



에코 프로토콜에서는 클라이언트에게 연결을 종료할 책임이 있다. 클라이언트에서 연결을 종료하지 않으면 영원히 연결을 유지할 수도 있기 때문에 많은 스레드와 함께 비동기 입출력의 지원이 중요해진다. 


아래 예제에서는 500개의 스레드를 생성한다.


package network;


import java.io.IOException;

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.nio.ByteBuffer;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

import java.util.Iterator;

import java.util.Set;


public class T55EchoServer {

public static int DEFAULT_PORT = 7;

public static void main(String[] args) {

int port;

try{

port = Integer.parseInt(args[0]);

}catch(RuntimeException e){

port = DEFAULT_PORT;

}

System.out.println(port + "번 포트에서 연결을 기다리고 있습니다.");

ServerSocketChannel serverChannel;

Selector selector;

try{

serverChannel = ServerSocketChannel.open();

ServerSocket ss = serverChannel.socket();

InetSocketAddress address = new InetSocketAddress(port);

ss.bind(address);

selector = Selector.open();

serverChannel.register(selector, SelectionKey.OP_ACCEPT);

}catch(IOException e){

e.printStackTrace();

return;

}

while(true){

try{

selector.select();

}catch(IOException e){

e.printStackTrace();

break;

}

}

Set<SelectionKey> readyKeys = selector.selectedKeys();

Iterator<SelectionKey> iterator = readyKeys.iterator();

while(iterator.hasNext()){

SelectionKey key = iterator.next();

try{

if(key.isAcceptable()){

ServerSocketChannel server = (ServerSocketChannel) key.channel();

SocketChannel client = server.accept();

System.out.println(client + "가 접속하였습니다.");

client.configureBlocking(false);

SelectionKey clientKey = client.register(

selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ);

ByteBuffer buffer = ByteBuffer.allocate(100);

clientKey.attach(buffer);

}

if(key.isReadable()){

SocketChannel client = (SocketChannel) key.channel();

ByteBuffer output = (ByteBuffer) key.attachment();

client.read(output);

}

if(key.isWritable()){

SocketChannel client = (SocketChannel) key.channel();

ByteBuffer output = (ByteBuffer) key.attachment();

output.flip();

client.write(output);

output.compact();

}

}catch(IOException e){

key.cancel();

try{

key.channel().close();

}catch(IOException ex){}

}

}

}

}