缓冲区 InputStream 未读取最后一个数据包
BufferInputStream not reading the last packet
我正在尝试将 apk 文件从一台设备发送到另一台设备。基本上,要发送的用户有一个带有他安装的应用程序(非系统应用程序)的 gridview,当用户按下其中一个应用程序的图标时,它会将其发送到另一台设备。文件被缓冲成更小的数据包。
我正在做一些系统输出来检查发生了什么,同时发送方设备正在发送 X 个数据包,接收方收到的数据包少于 X 个(这取决于正在发送的应用程序,所以这就是我写的原因X)。我认为这是最后一个丢失的。
我的缓冲区的长度是4096,而"last packet"只有2115。在接收端,它没有抛出读写文件后的系统输出。所以程序卡在了阅读指令上。 我的问题是为什么最后一个数据包没有被传输?
这是我的代码。
客户端 - apk 的发送者。
public class SendThread implements Runnable{
@Override
public void run() {
try {
if(clientSocket==null){
clientSocket=new Socket(serverIP,porto);
System.out.println("client comm - Created the client socket..");
}
System.out.println(" client comm, i am here in the send thread, going to create the outputstream object");
if(out==null){
out = new ObjectOutputStream(clientSocket.getOutputStream());
System.out.println(" Client COMM SEND THREAD - JUST created the outputstream .");
}
File apkToSend=new File(filePath);
byte[] buffer = new byte [4096];
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(apkToSend));
int count;
int total=0;
while((count=bis.read(buffer,0,4096))!=-1){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
out.write(buffer,0,count);
total+=count;
out.flush();
System.out.println("Client Comm send thread - already sent this ammount : "+total);
}
bis.close();
out.flush();
System.out.println("clientComm send thread - Just sent the message ! i am after the out.writeOBject. Not saving it to a string yet.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
现在是服务器端——接收文件的设备..
public class ReceiveThread implements Runnable{
@Override
public void run() {
try {
if(socket==null){
socket=serverSocket.accept();
System.out.println("serverComm - accepted the socket from the client.");
out=new ObjectOutputStream(socket.getOutputStream());
out.writeObject("Hello client, i the server, sending you this message because i want to. SO that you unlock from the input stream creation");
System.out.println("SErverComm Created the output stream and sent a HEllo message to the client ");
}
if(in==null){
in = new ObjectInputStream(socket.getInputStream());
}
while(!serverSocket.isClosed()){
try {
if(!handshakeDone){
System.out.println("server comm receive thread - INSIDE THE WHILE CICLE, before the in.readObject");
String message = (String) in.readObject();
System.out.println("ServercomM receive thread - just did the handshake message control");
handshakeDone=true;
}else{
System.out.println("server comm receive thread - INSIDE THE WHILE CICLE, before the in.readObject");
File apkReceived = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/testeReceiveServerComm.apk");
byte[] buffer = new byte [4096];
BufferedInputStream bis=new BufferedInputStream(in);
FileOutputStream fos=new FileOutputStream(apkReceived);
int count=0;
int total=0;
while((count=bis.read(buffer,0,4096))!=-1){
fos.write(buffer,0,count);
total+=count;
System.out.println("Server Comm receive thread - already received this ammount : "+total);
}
;
System.out.println("Already received everything ! ");
fos.flush();
bis.close();
fos.close();
System.out.println(" server comm receive thread - already read the object !!!!!!!!!!!!!!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里有很多谬论。
the sender device is sending X packets meanwhile, the receiver is receiving less than X packets
您没有对数据包进行计数,所以您不可能知道这一点。在任何情况下,接收到的 'packets' 的数量与 TCP 中发送的数量无关。重要的是 字节 的数量,这里没有证据表明您丢失了任何字节。您所看到的是,当您的缓冲区大小为 4096 时,最后一次读取返回了 2115 个字节。这意味着输入文件的大小为 N*4096+2115,而不是 4096 的倍数。
您正在使用 ObjectInputStream
和 ObjectOutputStream
但您只发送字节。您可以为此使用套接字自己的输入和输出流:无需支付字节流的额外开销。
- 你毫无意义地包装了一个
BufferedInputStream
*aroundthe
ObjectInputStream`。应该是反过来的。
- 旅游代码中的
Thread.sleep()
简直就是浪费时间。和 space。删除它。
- 您正在套接字关闭后刷新输出流。您应该关闭 output 流,而不是输入流,关闭它会使刷新变得多余。
- 您还必须捕获并忽略由
flush()
产生的 IOException
,除非您非常幸运并且没有什么可刷新的。我不知道这怎么可能,因为您的文件不是缓冲区大小的倍数。
- 您正在使用
while (!serverSocket.isClosed())
作为从接受的套接字读取的终止测试。这毫无意义。
- 您的接收线程同时接受和处理单个连接。这使您的整个服务器成为单线程。应该有一个用于接受的线程,以及处理每个接受的套接字的线程。
您需要仔细阅读网络教程,例如 Oracle Java 教程的自定义网络部分。这不是写网络代码的方法。
我正在尝试将 apk 文件从一台设备发送到另一台设备。基本上,要发送的用户有一个带有他安装的应用程序(非系统应用程序)的 gridview,当用户按下其中一个应用程序的图标时,它会将其发送到另一台设备。文件被缓冲成更小的数据包。
我正在做一些系统输出来检查发生了什么,同时发送方设备正在发送 X 个数据包,接收方收到的数据包少于 X 个(这取决于正在发送的应用程序,所以这就是我写的原因X)。我认为这是最后一个丢失的。
我的缓冲区的长度是4096,而"last packet"只有2115。在接收端,它没有抛出读写文件后的系统输出。所以程序卡在了阅读指令上。 我的问题是为什么最后一个数据包没有被传输?
这是我的代码。
客户端 - apk 的发送者。
public class SendThread implements Runnable{
@Override
public void run() {
try {
if(clientSocket==null){
clientSocket=new Socket(serverIP,porto);
System.out.println("client comm - Created the client socket..");
}
System.out.println(" client comm, i am here in the send thread, going to create the outputstream object");
if(out==null){
out = new ObjectOutputStream(clientSocket.getOutputStream());
System.out.println(" Client COMM SEND THREAD - JUST created the outputstream .");
}
File apkToSend=new File(filePath);
byte[] buffer = new byte [4096];
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(apkToSend));
int count;
int total=0;
while((count=bis.read(buffer,0,4096))!=-1){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
out.write(buffer,0,count);
total+=count;
out.flush();
System.out.println("Client Comm send thread - already sent this ammount : "+total);
}
bis.close();
out.flush();
System.out.println("clientComm send thread - Just sent the message ! i am after the out.writeOBject. Not saving it to a string yet.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
现在是服务器端——接收文件的设备..
public class ReceiveThread implements Runnable{
@Override
public void run() {
try {
if(socket==null){
socket=serverSocket.accept();
System.out.println("serverComm - accepted the socket from the client.");
out=new ObjectOutputStream(socket.getOutputStream());
out.writeObject("Hello client, i the server, sending you this message because i want to. SO that you unlock from the input stream creation");
System.out.println("SErverComm Created the output stream and sent a HEllo message to the client ");
}
if(in==null){
in = new ObjectInputStream(socket.getInputStream());
}
while(!serverSocket.isClosed()){
try {
if(!handshakeDone){
System.out.println("server comm receive thread - INSIDE THE WHILE CICLE, before the in.readObject");
String message = (String) in.readObject();
System.out.println("ServercomM receive thread - just did the handshake message control");
handshakeDone=true;
}else{
System.out.println("server comm receive thread - INSIDE THE WHILE CICLE, before the in.readObject");
File apkReceived = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/testeReceiveServerComm.apk");
byte[] buffer = new byte [4096];
BufferedInputStream bis=new BufferedInputStream(in);
FileOutputStream fos=new FileOutputStream(apkReceived);
int count=0;
int total=0;
while((count=bis.read(buffer,0,4096))!=-1){
fos.write(buffer,0,count);
total+=count;
System.out.println("Server Comm receive thread - already received this ammount : "+total);
}
;
System.out.println("Already received everything ! ");
fos.flush();
bis.close();
fos.close();
System.out.println(" server comm receive thread - already read the object !!!!!!!!!!!!!!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里有很多谬论。
the sender device is sending X packets meanwhile, the receiver is receiving less than X packets
您没有对数据包进行计数,所以您不可能知道这一点。在任何情况下,接收到的 'packets' 的数量与 TCP 中发送的数量无关。重要的是 字节 的数量,这里没有证据表明您丢失了任何字节。您所看到的是,当您的缓冲区大小为 4096 时,最后一次读取返回了 2115 个字节。这意味着输入文件的大小为 N*4096+2115,而不是 4096 的倍数。
您正在使用
ObjectInputStream
和ObjectOutputStream
但您只发送字节。您可以为此使用套接字自己的输入和输出流:无需支付字节流的额外开销。- 你毫无意义地包装了一个
BufferedInputStream
*aroundthe
ObjectInputStream`。应该是反过来的。 - 旅游代码中的
Thread.sleep()
简直就是浪费时间。和 space。删除它。 - 您正在套接字关闭后刷新输出流。您应该关闭 output 流,而不是输入流,关闭它会使刷新变得多余。
- 您还必须捕获并忽略由
flush()
产生的IOException
,除非您非常幸运并且没有什么可刷新的。我不知道这怎么可能,因为您的文件不是缓冲区大小的倍数。 - 您正在使用
while (!serverSocket.isClosed())
作为从接受的套接字读取的终止测试。这毫无意义。 - 您的接收线程同时接受和处理单个连接。这使您的整个服务器成为单线程。应该有一个用于接受的线程,以及处理每个接受的套接字的线程。
您需要仔细阅读网络教程,例如 Oracle Java 教程的自定义网络部分。这不是写网络代码的方法。