Java TCP 心跳无法正常工作

标签 java android sockets tcp ioexception

项目:我一直在开发一款适用于 Android 的无线鼠标应用程序,它利用 TCP 作为传输鼠标移动的网络协议(protocol)。

目标: 我认为实现心跳 TimerTask 将是查看服务器是否已关闭的最佳方法。每 5 秒没有进行鼠标移动(鼠标移动会将计时器重置回 5),就会向服务器发送一个数组中 2 个字节的心跳。因此,如果服务器关闭,一旦发送心跳,就会引发 IOException (Broken Pipe)

我的问题: 除了在抛出异常之前循环 3 次之外,心跳工作正常。目前,我将其设置为 5 秒后发送心跳。在服务器关闭后,它将发送三个心跳(15 秒而不是 5 秒),然后引发预期的异常。

我可以将心跳间隔设置为 2 秒,这反过来应该需要 6 秒来引发异常,但我想知道为什么它第一次不起作用。

心跳代码:

 Timer task = new Timer();
                task.scheduleAtFixedRate(new TimerTask() {
                    @Override
                    public void run() {
                        if (heartbeat == 1) {
                            byte buf[] = {-96, -96};
                            try {
                                bos.write(buf); // Buffered output stream
                                bos.flush(); // Exception gets thrown here
                                heartbeat = 5;
                                System.out.println("Testing 3");
                            } catch (IOException e) {
                                System.out.println("Testing 2");
                                launchHomescreen();
                                this.cancel();
                                e.printStackTrace();
                            }
                        } else {
                            System.out.println("Testing 1" + heartbeat);
                            heartbeat--;
                        }
                    }
                }, 1000, 1000);

调试语句日志:

04-27 00:33:02.339  25410-26259/com.tutorials.jurko.androidmouse I/System.out﹕ Message sending: -99 -99 <-- This is the mouse click that should stop the server
04-27 00:33:03.190  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 15
04-27 00:33:04.201  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 14
04-27 00:33:05.192  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 13
04-27 00:33:06.193  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 12
04-27 00:33:07.203  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 3 <- Should throw the exception here
04-27 00:33:08.194  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 15
04-27 00:33:09.195  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 14
04-27 00:33:10.196  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 13
04-27 00:33:11.187  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 12
04-27 00:33:12.188  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 3
04-27 00:33:13.189  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 15
04-27 00:33:14.190  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 14
04-27 00:33:15.191  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 13
04-27 00:33:16.202  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 12
04-27 00:33:17.193  25410-26264/com.tutorials.jurko.androidmouse I/System.out﹕ Testing 2 <- but doesn't do it till the third heartbeat
04-27 00:33:17.233  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ java.net.SocketException: sendto failed: EPIPE (Broken pipe)
04-27 00:33:17.243  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:499)
04-27 00:33:17.243  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at libcore.io.IoBridge.sendto(IoBridge.java:468)
04-27 00:33:17.243  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at java.net.PlainSocketImpl.write(PlainSocketImpl.java:508)
04-27 00:33:17.243  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at java.net.PlainSocketImpl.access$100(PlainSocketImpl.java:46)
04-27 00:33:17.243  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at java.net.PlainSocketImpl$PlainSocketOutputStream.write(PlainSocketImpl.java:270)
04-27 00:33:17.243  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at java.io.BufferedOutputStream.flushInternal(BufferedOutputStream.java:185)
04-27 00:33:17.243  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:85)
04-27 00:33:17.243  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at com.tutorials.jurko.androidmouse.MainActivity$connectTask$1.run(MainActivity.java:496)
04-27 00:33:17.243  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at java.util.Timer$TimerImpl.run(Timer.java:284)
04-27 00:33:17.243  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ Caused by: libcore.io.ErrnoException: sendto failed: EPIPE (Broken pipe)
04-27 00:33:17.243  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at libcore.io.Posix.sendtoBytes(Native Method)
04-27 00:33:17.253  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at libcore.io.Posix.sendto(Posix.java:156)
04-27 00:33:17.253  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:177)
04-27 00:33:17.253  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ at libcore.io.IoBridge.sendto(IoBridge.java:466)
04-27 00:33:17.253  25410-26264/com.tutorials.jurko.androidmouse W/System.err﹕ ... 7 more
04-27 00:33:17.453  25410-25410/com.tutorials.jurko.androidmouse W/ApplicationPackageManager﹕ getCSCPackageItemText()
04-27 00:33:33.139  25410-25410/com.tutorials.jurko.androidmouse W/IInputConnectionWrapper﹕ getCursorCapsMode on inactive InputConnection

最佳答案

由于 TCP 缓冲和异步性,“连接重置”/“管道损坏”不会立即发生。它发生在写入事件因未收到 ACK 而超时后,这可能需要相当长的一分钟时间。

它不一定与写入尝试次数相关,因此更改间隔不一定有帮助。

关于Java TCP 心跳无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29887295/

相关文章:

linux - linux 上的 C 套接字编程

java - 如何获取JTextArea中的指定行

java - 两次异步操作后更新 UI

Android:为 MySQL 和 SQLite 数据库设计

android - 使用 NDK 在 C/C++ 中将 YUV 解码为 RGB

javascript - node.js 和 heroku 上的 socket.io,空闲超时错误

java - 在反序列化 Json 时,如何在 jackson 中确定 POJO 的 setter 方法调用的顺序?

java - 读取巨大的 txt 文件时超出 GC 开销限制

java - 错误 :com. android.dex.DexIndexOverflowException : method ID not in [0, 0xffff]:65536

c# - 为什么不能递归调用Worker_DoWork函数?