네트워크 파일 전송은 자바 네티를 사용하여 간단하게 구현할 수 있습니다. 자바 네티는 자바로 빠르고 안정적인 네트워크 애플리케이션을 구축하기 위해 디자인된 프레임워크입니다. 이를 사용하여 파일을 전송하는 방법을 알아보겠습니다.
1. 프로젝트 설정
먼저, 자바 네티를 사용하기 위해 프로젝트에 아래의 Maven 의존성을 추가해야 합니다.
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.52.Final</version>
</dependency>
2. 서버 구현
파일을 전송할 서버를 구현해야 합니다. 아래는 간단한 예시 코드입니다.
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.stream.ChunkedWriteHandler;
public class FileServer {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new ChunkedWriteHandler());
ch.pipeline().addLast(new FileServerHandler());
}
});
ChannelFuture future = bootstrap.bind(8080).sync();
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
위의 예시 코드에서는 NioEventLoopGroup
으로 이벤트 루프 그룹을 생성하고, ServerBootstrap
을 사용하여 서버를 구성합니다. 핸들러로는 ChunkedWriteHandler
와 FileServerHandler
를 추가하여 파일 전송을 처리합니다.
3. 클라이언트 구현
파일을 전송하는 클라이언트도 구현해야 합니다. 아래는 클라이언트의 예시 코드입니다.
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import java.io.File;
import java.io.RandomAccessFile;
public class FileClient {
public static void main(String[] args) throws Exception {
String fileName = "path/to/file.txt";
File file = new File(fileName);
RandomAccessFile raf = new RandomAccessFile(file, "r");
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new LineBasedFrameDecoder(8192));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new FileClientHandler(raf));
}
});
ChannelFuture future = bootstrap.connect("localhost", 8080).sync();
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
raf.close();
}
}
}
위의 예시 코드에서는 NioEventLoopGroup
으로 이벤트 루프 그룹을 생성하고, Bootstrap
을 사용하여 클라이언트를 구성합니다. 핸들러로는 LineBasedFrameDecoder
, StringDecoder
, 그리고 FileClientHandler
를 추가하여 파일 전송을 처리합니다.
4. 핸들러 구현
서버 및 클라이언트에서 사용되는 핸들러들을 구현해야 합니다. 아래는 간단한 FileServerHandler
와 FileClientHandler
예시 코드입니다.
FileServerHandler:
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import java.io.FileOutputStream;
public class FileServerHandler extends ChannelInboundHandlerAdapter {
private static final String FILE_PATH = "path/to/save/directory/";
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
try (FileOutputStream fos = new FileOutputStream(FILE_PATH)) {
while (byteBuf.isReadable()) {
byteBuf.readBytes(fos, byteBuf.readableBytes());
}
ctx.writeAndFlush("File received successfully");
} finally {
byteBuf.release();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
FileClientHandler:
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import java.io.RandomAccessFile;
public class FileClientHandler extends ChannelInboundHandlerAdapter {
private final RandomAccessFile raf;
private long transferredBytes = 0;
public FileClientHandler(RandomAccessFile raf) {
this.raf = raf;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(raf.length() + "\n");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof String) {
long length = Long.parseLong((String) msg);
if (length == transferredBytes) {
ctx.close();
System.out.println("File transferred successfully");
} else {
ctx.writeAndFlush(raf.getChannel().map(FileChannel.MapMode.READ_ONLY, transferredBytes, length - transferredBytes));
}
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
transferredBytes += raf.length();
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
5. 실행
위의 서버와 클라이언트 코드를 각각 실행하여 파일 전송을 테스트할 수 있습니다.
자바 네티를 사용하여 네트워크 파일 전송을 구현하는 방법을 알아보았습니다. 자세한 내용은 자바 네티 공식 문서를 참고하시기 바랍니다.
참고 문서: Java Netty 공식 문서