我尝试使用Java NIO API将mp3文件从服务器传输到客户端。
特别是,我正在尝试使用transferTo& transferFrom方法。
我已经检查过服务器是否正确识别该文件并转移到FileChannel。
但是,从客户端的角度来看,它认为连接到服务器的FileChannel的大小为0,可以解释为客户端没有从通道接收任何文件。
以下是服务器和客户端控制台的结果。
[服务器]
Server is started...
java.nio.channels.SocketChannel[connected local=/127.0.0.1:7777 remote=/127.0.0.1:60430]Here comes a new client!
!!write activated!!
Channel size : 3622994
filename : C:\Users\InhoKim\Music\5 O'clock - Black Nut.mp3
java.nio.channels.SocketChannel[connected local=/127.0.0.1:7777 remote=/127.0.0.1:60430]The number of files transferred : 1
[客户]
!!read activated!!
Channel size : 0
我该如何解决这个问题?
以下是服务器和客户端的完整代码
[服务器]
import java.io.File;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.net.ServerSocket;
import java.net.InetSocketAddress;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.channels.FileChannel;
import java.io.FileInputStream;
import java.util.Set;
import java.nio.ByteBuffer;
public class MusicServer {
private Selector selector = null;
private ServerSocketChannel serverSocketChannel = null;
private ServerSocket serverSocket = null;
File dir = new File("C:\\Users\\InhoKim\\Music\\");
boolean test = true;
public static void main(String[] args) {
MusicServer ms = new MusicServer();
ms.initServer();
ms.startServer();
}
public void initServer() {
try {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocket = serverSocketChannel.socket();
InetSocketAddress isa = new InetSocketAddress("localhost", 7777);
serverSocket.bind(isa);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch(Exception e) {e.printStackTrace();}
}
public void startServer() {
System.out.println("Server is started...");
try {
while (true) {
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
for (SelectionKey key : keys) {
SelectableChannel channel = key.channel();
if (channel instanceof ServerSocketChannel) {
if (key.isAcceptable())
accept(key);
} else {
if (key.isWritable()) {
if(test)
write(key);
}
}
}
}
} catch(Exception e) {e.printStackTrace();}
}
private void accept(SelectionKey key) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
try {
SocketChannel sc = server.accept();
if (sc == null) return;
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_WRITE);
System.out.println(sc.toString() + "Here comes a new client!");
} catch(Exception e) {e.printStackTrace();}
}
private void write(SelectionKey key) {
if(test)
System.out.println("!!write activated!!");
test = false;
SocketChannel sc = (SocketChannel) key.channel();
try {
File[] files = dir.listFiles();
int count = 0;
for (File file : files) {
count++;
FileInputStream fis = new FileInputStream(file);
FileChannel inChannel = fis.getChannel();
System.out.println("Channel size : " + (int)inChannel.size());
System.out.println("filename : " + file);
inChannel.transferTo(0, (int)inChannel.size(), sc);
fis.close();
break;
}
System.out.println(sc.toString() + "The number of files transferred : " + count);
} catch(Exception e) {e.printStackTrace();}
}
}
[客户]
import java.io.File;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.channels.SelectionKey;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.util.Set;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
public class MusicClient {
private Selector selector = null;
private SocketChannel sc = null;
int count = 0;
public static void main(String[] args) {
MusicClient mc = new MusicClient();
mc.startServer();
}
public void initServer() {
try {
selector = Selector.open();
sc = SocketChannel.open(new InetSocketAddress("127.0.0.1", 7777));
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
} catch(Exception e) {e.printStackTrace();}
}
public void startServer() {
initServer();
startReader();
}
public void startReader() {
try {
while (true) {
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
for (SelectionKey key : keys) {
if (key.isReadable()) {
read(key);
System.exit(0);
}
}
}
} catch(Exception e) {e.printStackTrace();}
}
private void read(SelectionKey key) {
System.out.println("!!read activated!!");
SocketChannel sc = (SocketChannel) key.channel();
try {
File dir = new File("D:\\Target2\\");
FileOutputStream fos = new FileOutputStream(dir + "\\" + count + ".mp3"); // file name has been set as a number
count++;
FileChannel outChannel = fos.getChannel();
System.out.println("Channel size : " + (int)outChannel.size());
outChannel.transferFrom(sc, 0, (int)outChannel.size());
fos.close();
} catch(Exception e) {e.printStackTrace();}
}
}
答案 0 :(得分:1)
从客户端的角度来看,它认为连接到服务器的FileChannel的大小是0
没有&#39; FileChannel
连接到服务器&#39;。文件通道连接到文件。您所拥有的是FileChannel
连接到刚刚创建了一个新文件的新FileOutputStream
,因此该文件的大小为零。
可以解释为客户端没有从频道收到任何文件。
不,它可以解释为你告诉FileChannel
传输零字节,它正确地做了。
您无法获得SocketChannel
的大小,因为它并不意味着任何事情(考虑只是一直发送并且永远不会关闭连接的对等方)。因此,在这种情况下,您必须使用Long.MAX_VALUE
作为大小。当没有更多字节要传输时,或者实际上之前,传输将完成,特别是当您使用非阻塞模式时。
编辑我没有看到在客户端使用非阻止模式的任何理由。我会删除它,并且必须在循环中调用Selector.
和transferFrom()
,该循环在返回零时终止。如果必须在那里使用非阻塞模式,则在服务器中使用transferTo()
要复杂得多,因为当它返回零时必须注册OP_WRITE
并在获得时使用调整后的偏移量重新选择并重新启动如果它没有返回零,则取消注册OP_WRITE
。