네트워크 파일 전송은 자바 네티를 사용하여 간단하게 구현할 수 있습니다. 자바 네티는 자바로 빠르고 안정적인 네트워크 애플리케이션을 구축하기 위해 디자인된 프레임워크입니다. 이를 사용하여 파일을 전송하는 방법을 알아보겠습니다.
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 공식 문서