Java 套接字连接已断开一半-未引发IOException

Java 套接字连接已断开一半-未引发IOException,java,android,sockets,exception,networking,Java,Android,Sockets,Exception,Networking,我在这里读了一些关于这个问题的答案,但我对它们不满意,所以我决定自己去问。所以我知道也有类似的问题,但因为答案对我来说并不适用,我问自己 我有一个应用程序,可以让两个用户互相连接(一个作为服务器,另一个作为客户端)。他们将通过该套接字连接发送文件。我正在使用一个包含两个线程的服务,一个用于读取,另一个用于发送用户选择的文件 问题在于:如果客户端通过在android菜单(正在运行的应用程序)上滑动应用程序来关闭应用程序,然后服务器(另一个家伙)尝试向他发送内容,我认为它应该抛出IOExceptio

我在这里读了一些关于这个问题的答案,但我对它们不满意,所以我决定自己去问。所以我知道也有类似的问题,但因为答案对我来说并不适用,我问自己

我有一个应用程序,可以让两个用户互相连接(一个作为服务器,另一个作为客户端)。他们将通过该套接字连接发送文件。我正在使用一个包含两个线程的服务,一个用于读取,另一个用于发送用户选择的文件

问题在于:如果客户端通过在android菜单(正在运行的应用程序)上滑动应用程序来关闭应用程序,然后服务器(另一个家伙)尝试向他发送内容,我认为它应该抛出IOException,因为套接字流的另一端已经结束。但它没有这样做,我不知道为什么。如果我想给离开的人送点东西,我想敬酒。

编辑:刚刚注意到它总是在指令out.reset()处停止

你们知道为什么不抛出那个异常吗? 可能的解决办法是什么

PS:这是一个lite应用程序,所以发送保持活动的消息不是一个好的解决方案。而且,它已经向祝酒人展示了我有一两次,但是我不能再重复这种行为了

这是我的代码,我不想发生这种情况:

   ClientHandler tmp = connectedClients.get(key);
                    ObjectOutputStream out = tmp.getOut();
                    Socket s = tmp.getSocket();

                    if(s.isClosed()){
                        System.out.println("The socket of this client "+key + " is closed!");
                    }

                    if(s.isOutputShutdown()){
                        System.out.println("The output of this client is shutdown !");//only checks this side, the other one is the one that is shutdown
                    }
                    System.out.println("changed the culpado to : "+1);
                    createSendNotification();

                    File apkToSend;

                    for(int i=0;i<listOfApps.size();i++){
                        System.out.println("Item do be sent is : "+i);
                        HighwayGridViewAppItem tmpItem=listOfApps.get(i);
                        filePath=tmpItem.getFilePath();
                        appName=tmpItem.getAppName();
                        System.out.println("his filepath to send is : "+filePath);
                        System.out.println("his appname to send is : "+appName);


                        couldSend=false;

                        apkToSend=new File(filePath);

                        if(apkToSend.exists()){//do i reallly need this if?

                            apkToSendSize=apkToSend.length();
                            System.out.println("File size: " +apkToSendSize);

                            try{
                                out.writeObject(appName +": "+ apkToSendSize);//appName to send to have the name of the file

                                byte[] buffer = new byte [8192];
                                BufferedInputStream bis=new BufferedInputStream(new FileInputStream(apkToSend));
                                int count;
                                totalToSend =0;
                                showSendProgress();

                                while((count=bis.read(buffer))!=-1){
                                    out.write(buffer,0,count);
                                    totalToSend +=count;
                                    out.reset();
                                    System.out.println("ServerComm send thread - already sent this ammount : "+ totalToSend);
                                }
                                out.flush();
                                bis.close();

                            }
                            catch ( IOException e){

                                System.out.println("It is throwing the input output exception");

                                e.printStackTrace();

                                connectedClients.remove(key);
                                if(clients.size()<=1){

                                    h.post(new Runnable() {
                                        @Override
                                        public void run() {
                                            Toast.makeText(context, "No one is in your group.", Toast.LENGTH_SHORT).show();
                                        }
                                    });

                                    i=listOfApps.size()+1;
                                }else{

                                    System.out.println("Has more than one");
                                }

                            }
ClientHandler tmp=connectedClients.get(key);
ObjectOutputStream out=tmp.getOut();
套接字s=tmp.getSocket();
如果(s.isClosed()){
System.out.println(“此客户端的套接字“+key+”已关闭!”);
}
如果(s.isOutputShutdown()){
System.out.println(“此客户端的输出已关闭!”);//只检查这一侧,另一侧是已关闭的一侧
}
System.out.println(“将culpado更改为:”+1);
createSendNotification();
文件apkToSend;

对于(int i=0;i仅仅因为Android处理了一个应用程序并不意味着在内部关闭了所有打开的连接,很可能你需要检测Android事件,然后执行显式关闭打开的套接字的代码,而不是等待Android最终处理它。否则,你将不得不等待垃圾回收调用终结器关闭的套接字


这里的这篇文章详细介绍了Android事件,特别是onDestroy方法:

仅仅因为Android处理了一个应用程序并不意味着在内部关闭了所有打开的连接,你很可能需要检测Android事件,然后执行显式关闭打开的套接字的代码,而不是w等待Android最终处理它。否则,你将不得不等待垃圾收集调用终结器关闭套接字


这篇文章详细介绍了Android事件,特别是onDestroy方法:

如果您需要立即断开连接检测,那么您必须实现自己的ping/keep-alive机制,这通常意味着发送数据包并持续确认,以便能够更可靠地捕获异常

如果您需要立即断开连接检测,那么您必须实现自己的ping/保持活动机制,这通常意味着发送数据包并持续确认它们,以便能够更可靠地捕获异常。

您没有太多选择。您必须等待TCP要求的时间来检测中断,而ch包括发送重试超时。我可以让等待变小吗?奇怪的是,它写了,然后停止写,什么也不做。就像什么都没发生一样。另外,奇怪的是,它在正确的时间抛出异常2到3次,然后我做了一些小的更改,比如添加system.out.println,当我注意到ed,它不再工作了,这是非常愚蠢的。你必须记住TCP发送是缓冲的和异步的。所以很多写操作都会成功,因为它们只是缓冲区,然后写操作会被阻塞,因为缓冲区已满并且没有被ACK耗尽,然后你在写操作中被阻塞,直到触发重试超时,然后你会得到一个co连接重置。每次发送内容时,我都会重置流,我注意到,当某些写入成功时,它会在重置中阻塞。关于它在重置中阻塞的原因的逻辑()同样是这样吗?你没有太多选择。你必须等待TCP检测中断所需的时间,包括发送重试超时。我可以让等待时间变小吗?奇怪的是,它会写入,然后停止写入,什么也不做。就像什么都没发生一样。另外,奇怪的是,它在t处抛出异常他用了两三次正确的时间,然后我做了一些小的更改,比如添加了system.out.println,当我注意到它不再工作时,这是非常愚蠢的。你必须记住TCP发送是缓冲的和异步的。所以很多写操作都会成功,因为它们只有缓冲区,然后写操作会阻塞,因为缓冲区已满且没有被ACK耗尽,那么在重试超时被触发之前,您的写入会被阻止,然后您会得到一个连接重置。我每次发送内容时都会重置流,并且我注意到,当一些写入成功时,它会在重置中被阻止。关于它在重置()中被阻止的原因的逻辑是相同的,对吗?