【发布时间】:2017-02-17 01:57:22
【问题描述】:
我在这里阅读了一些关于这个问题的答案,但我对它们并不满意,所以我决定自己问。所以我知道有类似的问题,但由于答案对我来说真的不起作用,所以我问自己。
我有一个应用程序可以让 2 个用户相互连接(一个用作服务器,另一个用作客户端)。他们将通过该套接字连接发送文件。我正在使用一个内部有 2 个线程的服务,一个用于读取,另一个用于发送用户选择的文件。
这就是问题所在:如果客户端通过在(正在运行的应用程序的)android 菜单上滑动它来关闭应用程序,然后服务器(另一个人)试图向他发送一些东西,在我的认为它应该抛出一个 IOException,因为套接字流的另一端已经结束。但它没有这样做,我不知道为什么。如果我尝试向离开的人发送一些东西,我想展示一个 Toast。
编辑:刚刚注意到它总是停在指令 out.reset();
你们中的任何人都知道为什么没有抛出该异常吗? 有什么可能的解决方案。
PS:这是一个精简的应用程序,所以发送 Keep Alive 消息不是一个好的解决方案。此外,它已经向我展示了一两次吐司,但我无法再次复制这种行为。
这是我不希望发生的代码:
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");
}
}
PS:当我尝试发送到“关闭”客户端时,它会打印一些“ServerComm 发送线程 - 已发送此数量:”+ totalToSend”,但随后停止,这是我认为应该抛出异常,但它只是停止,并且没有给出任何错误,应用程序继续它的生命,但我需要向用户提供一些输入,说明某些问题出现了。
另外,我在此服务的 onCreate 方法中创建了该处理程序,它正在与主循环器正确创建(因为它在服务中,它需要不同的创建)。
提前谢谢你们。
编辑:最终,差不多 4 分钟后,它抛出了一个 SocketException,但我不能等那么久。
【问题讨论】:
-
您别无选择。只要 TCP 需要检测中断,您就必须等待,其中包括发送重试超时。
-
我可以缩短等待时间吗?奇怪的是它写了,然后它停止写,什么都不做。就像什么都没发生一样。
-
另外,奇怪的是它在正确的时间抛出了 2 到 3 次异常,然后我做了一些小的改动,比如添加了一个 system.out.println,当我注意到时,它没有再次工作,这很愚蠢。
-
您必须记住 TCP 发送是缓冲的和异步的。因此,许多写入将成功,因为它们仅缓冲,然后写入将阻塞,因为缓冲区已满并且没有被 ACK 耗尽,然后您在写入中被阻塞,直到触发重试超时,然后您获得连接重置.
-
我每次发送内容时都会重置流,我注意到当某些写入成功时,它会在重置中阻塞。在 reset() 中阻塞的原因逻辑是一样的吧?
标签: java android sockets exception networking