Java: SocketChannel.read() работает только один раз за выполнение программы на FTP-сервере
Мне было предложено выполнить это упражнение с просьбой создать простой FTP-сервер, где клиент запрашивает файл по имени файла с помощью SocketChannel, сервер получает имя файла, открывает файловый канал для чтения файла и отправляет его клиенту. селектором.
Вот что я придумал: это сервер
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.Paths;
import java.net.*;
import java.util.*;
import java.io.IOException;
public class MainClassServer
{
public static final int BUFFER_DIM = 64;
public static int DEFAULT_PORT = 1919;
public static void main(String[] args)
{
int port;
try
{
port = Integer.parseInt(args[0]);
}
catch (RuntimeException ex)
{
port = DEFAULT_PORT;
}
System.out.println("Listening for connections on port " + port);
ServerSocketChannel serverChannel;
Selector selector;
try
{
serverChannel = ServerSocketChannel.open();
ServerSocket ss = serverChannel.socket();
InetSocketAddress address = new InetSocketAddress(port);
ss.bind(address);
serverChannel.configureBlocking(false);
selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}
catch (IOException ex)
{
ex.printStackTrace();
return;
}
while (true)
{
try
{
selector.select();
}
catch (IOException ex)
{
ex.printStackTrace();
break;
}
Set <SelectionKey> readyKeys = selector.selectedKeys();
Iterator <SelectionKey> iterator = readyKeys.iterator();
while (iterator.hasNext())
{
SelectionKey key = iterator.next();
iterator.remove();
try
{
if (key.isAcceptable())
{
ServerSocketChannel server = (ServerSocketChannel)key.channel();
SocketChannel client = server.accept();
System.out.println("Accepted connection from " + client);
client.configureBlocking(false);
SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE);
ByteBuffer filenameBuffer = ByteBuffer.allocate(256);
int nRead = client.read(filenameBuffer);
System.out.println("readed " + nRead);
filenameBuffer.flip();
String filenameString = new String(filenameBuffer.array()).trim();
System.out.println("filename is: " + filenameString);
FileChannel writeChannel = FileChannel.open(Paths.get(filenameString));
key2.attach(writeChannel);
}
else if (key.isWritable())
{
SocketChannel client = (SocketChannel)key.channel();
FileChannel fileChannel = (FileChannel)key.attachment();
ByteBuffer bytesRead = ByteBuffer.allocate(BUFFER_DIM);
int nRead = fileChannel.read(bytesRead);
System.out.println("i readed from the file channel some " + nRead);
if(nRead >= 0)
{
bytesRead.flip();
client.write(bytesRead);
}
else
{
fileChannel.close();
client.close();
}
}
}
catch (IOException ex)
{
key.cancel();
try
{
key.channel().close();
}
catch (IOException cex) {}
}
}
}
}
}
И это клиент:
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.net.*;
import java.io.IOException;
public class MainClassClient
{
public static int DEFAULT_PORT = 1919;
public static void main(String[] args)
{
if (args.length == 0)
{
System.out.println("Usage: java IntgenClient host [port]");
return;
}
int port;
try
{
port = Integer.parseInt(args[0]);
}
catch (RuntimeException ex)
{
port = DEFAULT_PORT;
}
try
{
SocketAddress address = new InetSocketAddress("127.0.0.1", port);
SocketChannel client = SocketChannel.open(address);
ByteBuffer filenameBuffer = ByteBuffer.allocate(args[1].length());
filenameBuffer.put(args[1].getBytes());
filenameBuffer.flip();
System.out.println("i wrote " + client.write(filenameBuffer));
ByteBuffer readBuffer = ByteBuffer.allocateDirect(1024*1024);
FileChannel downloadChannel = FileChannel.open(Paths.get("downloaded" + args[1]),
StandardOpenOption.CREATE, StandardOpenOption.WRITE);
while(client.read(readBuffer) != -1)
{
readBuffer.flip();
downloadChannel.write(readBuffer);
while(readBuffer.hasRemaining())
{
System.out.print((char)readBuffer.get());
}
readBuffer.clear();
}
downloadChannel.close();
client.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
}
Он отлично работает и загружает файлы, которые я ему передаю, но проблема в том, что он работает только один раз за каждое выполнение сервера. Если я снова запускаю клиент и спрашиваю тот же файл с сервером, который все еще открыт, то это то, что сервер дает мне.
Listening for connections on port 1919
Accepted connection from java.nio.channels.SocketChannel[connected local=/127.0.0.1:1919 remote=/127.0.0.1:49198]
Exception in thread "main" java.lang.NullPointerException
at MainClassServer.main(MainClassServer.java:105)
readed 0
filename is:
Ряд 105
int nRead = fileChannel.read(bytesRead);
Но вывод говорит мне, что SocketChannel.read()
сделано при регистрации ключа.
Я довольно новичок в селекторах и ненавижу их. Так что я делаю не так?