我对Java Socket编程的最新困境感到困惑,现在已经连续三天了。我使用NIO ByteBuffer和Channel将字节从客户端传输到服务器。我通过让客户端按顺序发送2个文件来测试我的代码 - 第一个文件总是到达但第二个文件总是丢失所以在哪里。我做了tcpdump,我看到了特定地址和端口的流量,但我无法破译pcap的文件(了解如何读取pcap文件中的所有语法)。
以某种方式,socketchannel.read(bytebuffer)不读取第二个文件的任何字节。 第一个文件没问题。它通过read命令,接收文件并响应。 第二个文件可以读取命令并响应。它没有收到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调用的runnable,它只将serversocket.accept()传递给ServersThread(套接字套接字)
这是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);
}
}
答案 0 :(得分:0)
阅读第一次上传时,您将一直读到流结束,包括所有第二个文件。所以当你去阅读第二个文件时,什么也没有了。您需要在文件之前向自己发送文件长度,并且只读取那么多字节。
答案 1 :(得分:0)
在用这些问题花了大约12天之后,我终于以某种方式解决了问题,即使我无法解释为什么问题首先发生。这个问题很棘手,因为它几乎一直都在发生。文件传递不一致。
我更改了应用程序的协议。
客户的原始协议 1.发送字符串顺序 2.发送实际文件 3.接收服务器的确认
客户端的新协议 1.发送字符串顺序 2.接收服务器的确认 3.发送实际文件 4.接收服务器的确认
由于新协议,发送文件变得一致。
非常感谢。