[java] NIO 소켓 프로그래밍 개념과 활용
소켓 프로그래밍이란?
소켓 프로그래밍(Socket Programming)은 네트워크 프로그래밍에서 가장 중요한 개념 중 하나입니다. 소켓은 컴퓨터 간에 데이터를 주고받는 데 사용되는 양방향 통신 채널입니다. 네트워크 응용 프로그램에서 소켓을 이용하여 데이터를 전송하고 받을 수 있습니다.
NIO(Nondominated Input/Output)란?
NIO는 Java에서 제공하는 비동기 입출력 기능을 의미합니다. 기존의 IO 기능은 입출력 작업 시에 블로킹이 발생하여 다른 작업을 수행할 수 없었습니다. 하지만 NIO는 비동기 입출력을 지원하여 입출력 작업이 완료되지 않은 상태에서도 다른 작업을 수행할 수 있습니다. 이러한 특징은 네트워크 프로그래밍에서 매우 유용하게 사용됩니다.
NIO 소켓 프로그래밍 활용
NIO 소켓 프로그래밍은 다수의 클라이언트와 서버 간 양방향 통신을 지원하는데 유용합니다. NIO를 이용하여 다수의 클라이언트 요청을 효율적으로 처리하고, 대규모 트래픽을 처리하는 시스템을 구현할 수 있습니다.
다음은 NIO 소켓 프로그래밍의 예제 코드입니다.
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
public class NIOServer {
private ServerSocketChannel serverSocketChannel;
private Selector selector;
private ByteBuffer buffer = ByteBuffer.allocate(1024);
private List<SocketChannel> clients = new ArrayList<>();
public NIOServer(int port) {
try {
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(port));
selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIO Server started on port " + port);
} catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
try {
while (true) {
int ready = selector.select();
if (ready == 0) {
continue;
}
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (!key.isValid()) {
continue;
}
if (key.isAcceptable()) {
accept(key);
} else if (key.isReadable()) {
read(key);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void accept(SelectionKey key) throws IOException {
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
SocketChannel channel = serverChannel.accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
clients.add(channel);
System.out.println("Connection accepted: " + channel.getRemoteAddress());
}
private void read(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
buffer.clear();
int bytesRead = channel.read(buffer);
if (bytesRead == -1) {
disconnect(channel);
return;
}
buffer.flip();
byte[] bytes = new byte[bytesRead];
buffer.get(bytes);
String message = new String(bytes);
System.out.println("Received message: " + message);
broadcast(channel, message);
}
private void disconnect(SocketChannel channel) throws IOException {
channel.close();
clients.remove(channel);
System.out.println("Connection closed: " + channel.getRemoteAddress());
}
private void broadcast(SocketChannel sender, String message) throws IOException {
for (SocketChannel channel : clients) {
if (channel != sender) {
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
channel.write(buffer);
buffer.clear();
}
}
}
public void stop() {
try {
selector.close();
serverSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
NIOServer server = new NIOServer(8080);
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> server.start());
try {
TimeUnit.SECONDS.sleep(60);
} catch (InterruptedException e) {
e.printStackTrace();
}
server.stop();
}
}
위의 예제 코드는 NIO를 활용하여 간단한 다중 클라이언트 채팅 서버를 구현한 코드입니다. 다수의 클라이언트가 서버에 연결되면서 서로 메시지를 주고받을 수 있습니다.
결론
NIO 소켓 프로그래밍은 네트워크 프로그래밍에서 매우 유용하게 사용됩니다. 비동기 입출력을 이용하여 다수의 클라이언트와의 효율적인 통신을 구현할 수 있습니다. Java의 NIO 기능을 활용해 다양한 소켓 프로그래밍을 개발해 보세요.
참고 자료:
- https://docs.oracle.com/javase/7/docs/api/java/nio/channels/SocketChannel.html
- https://www.baeldung.com/java-nio-selector