【发布时间】:2014-07-12 19:25:49
【问题描述】:
我对最近三天的 Java Socket 编程困境感到困惑。我使用 NIO ByteBuffer 和 Channel 将字节从客户端传输到服务器。我通过让客户端按顺序发送 2 个文件来测试我的代码 - 第一个文件总是到达,但第二个文件总是丢失,所以在哪里。我做了 tcpdump,我看到了特定地址和端口的流量,但我无法破译 pcap 的文件(了解如何读取 pcap 文件中的所有语法)。
socketchannel.read(bytebuffer) 没有读取第二个文件的任何字节。 第一个文件会好的。它通过读取命令,接收文件并响应。 第二个文件可以用于读取命令和响应。它没有收到 socketchannel.read 的任何文件得到 -1 --- 这就是问题所在。
请帮忙。这真是个疯狂的问题。
public class ServersThread implements Runnable
{
private Socket socket;
public ServersThread(Socket socket)
{
this();
this.socket = socket;
}
public void run()
{
try
{
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(isr);
PrintStream ps = new PrintStream(socket.getOutputStream(), true);
String orderFromClient = br.readLine(); // first read command from client
String filename = orderFromClient.split(":")[0]
long fileSize = Long.parseLong(orderFromClient.split(":")[1]);
File destFile = new File(filename);
destFile.setReadable(true);
destFile.setWritable(true);
FileOutputStream inFile = new FileOutputStream(destFile);
FileChannel inChannel = inFile.getChannel();
SocketChannel sc = socket.getChannel();
ByteBuffer dst = ByteBuffer.allocate(65536);
dst.clear();
// this receiving binary file part that is questionable.
// it always run okay for the first file
// the second file is created but always has size 0
// The second file will enter into while-loop start and end but it won't enter sc.read(dst)
logger.debug(AUDIT,"while-loop start");
start = System.currentTimeMillis();
while (sc.read(dst) != -1)
{
dst.flip();
logger.debug(AUDIT,"dst flip and ask remaining: {} at position {}",dst.hasRemaining(),dst.position());
while (dst.hasRemaining())
{
temp = inChannel.write(dst);
curnset += temp;
logger.debug(AUDIT, "c {} | t {} | size {}", curnset, temp, fileSize);
}
dst.clear();
}
end = System.currentTimeMillis();
logger.debug(AUDIT,"while-loop end");
if (curnset == fileSize)
ps.println("SUCCESS");
else
ps.println("FAIL");
}
catch(Exception e)
{
e.printStackTrace(System.err);
logger.error("Exception ",e);
}
finally
{
try
{
inChannel.close();
inFile.close();
sc.close();
ps.close();
isr.close();
br.close();
socket.close();
}
catch(IOException e)
{ }
}
}
}
ServerThread 实现了由其他类 ServerMain 调用的可运行对象,该类仅将 serversocket.accept() 传递给 ServersThread(Socket socket)
这里是 ServerMain 类:
public class ServerMain
{
public static void main(String[] args)
{
ServerSocketChannel listener = null;
ServerSocket serverMain = null;
try
{
listener = ServerSocketChannel.open();
serverMain = listener.socket();
serverMain.setReuseAddress(true);
serverMain.bind(new InetSocketAddress("192.168.1.12",9999));
while (true)
{
new ServersThread(serverMain.accept()).start();
}
}
catch (Exception e)
{
logger.error("Exception ", e);
e.printStackTrace(System.err);
}
finally
{
try
{
listener.close();
}
catch (IOException e)
{
logger.error("IOException ", e);
e.printStackTrace(System.err);
}
}
}
}
这里是客户端类
public class ClientCallable
{
public static void process(String serverAddr,int serverPort,File file,String command)
{
SocketChannel sc = null;
PrintStream ps = null;
BufferedReader br = null;
int timeout = 10 * 1000;
try
{
sc = SocketChannel.open();
sc.configureBlocking(true);
if (!sc.connect(new InetSocketAddress(serverAddr, serverPort)))
return ClientMain.ERROR_UNABLE_TO_CONNECT;
sc.socket().setSoTimeout(timeout);
}
catch (Exception e)
{
logger.error("Exception ", e);
e.printStackTrace(System.err);
return;
}
long maxCount = 8192 * 1024;
long curnset = 0l;
long temp = 0l;
long filesize = 0l;
long startTime = 0l;
long endTime = 0l;
String serverResp = null;
FileInputStream fis = null;
FileChannel fc = null;
try
{
ps = new PrintStream(sc.socket().getOutputStream());
br = new BufferedReader(new InputStreamReader(sc.socket()
.getInputStream()));
fis = new FileInputStream(file);
fc = fis.getChannel();
filesize = fc.size();
// send command to server
ps.print(command);
// send binary file
ByteBuffer dst = ByteBuffer.allocate(65536);
dst.clear();
startTime = System.currentTimeMillis();
while (fc.read(dst) != -1)
{
dst.flip();
while (dst.hasRemaining())
{
temp = sc.write(dst);
curnset += temp;
logger.debug(AUDIT, "c {} | t {} | size {}", curnset, temp,
filesize);
}
dst.clear();
}
sc.shutdownOutput();
endTime = System.currentTimeMillis();
// read server respond
serverResp = br.readLine();
logger.debug(AUDIT,"server responds {}",serverResp);
}
catch (Exception e)
{
logger.error("Exception ", e);
e.printStackTrace(System.err);
}
try
{
if (fis != null)
fis.close();
if (fc != null)
fc.close();
if (ps != null)
ps.close();
if (br != null)
br.close();
if (sc != null)
sc.close();
}
catch (Exception e)
{
logger.error("Exception ", e);
e.printStackTrace(System.err);
}
}
public static void main(String[] args)
{
String serverAddr = "192.168.1.12"
int serverPort = 9999;
File file1 = new File("file1.fpt");
File file2 = new File("file2.fpt");
String command = "somecommandtoserver";
process(serverAddr,serverPort,file1,command);
process(serverAddr,serverPort,file2,command);
}
}
【问题讨论】:
-
我已经使用 tcpdump 和 wireshark 验证了客户端发送数据并且服务器按计划接收到字节。我研究了wireshark和pcap文件的ACK、PSH ACK、SYN、FIN ACK。然而,在 java 的级别, sc.read(dst) != 1 仍在发生!非常令人费解!有人提出建议吗?我现在无计可施。
标签: java sockets socketchannel