OutputStream.write()成功,但此数据未送达
我在写一个插座一个很奇怪的行为。 在我的移动客户端我使用的是初始化的插槽如下:
I have a very strange behaviour during writing to a socket. In my mobile client I'm using a socket which is initialized as follows:
private void initSocket()
{
socket = new Socket();
socket.connect(new InetSocketAddress(host, port));
os = new DataOutputStream(socket.getOutputStream());
is = new DataInputStream(socket.getInputStream());
}
然后定期(每60秒),我阅读和写一些数据,这个插座(在code这里是一个有点简单):
then periodically (every 60 seconds) I read and write some data to this socket (the code here is a little bit simplified):
if(!isSocketInitialized())
{
initSocket();
}
byte[] msg = getMessage();
os.write(msg);
os.flush();
int bytesAvailable = is.available( );
if(bytesAvailable>0)
{
byte[] inputBuffer = new byte[bytesAvailable];
int numRead = is.read(inputBuffer, 0, bytesAvailable);
processServerReply(inputBuffer, numRead);
}
和它的作品。但是......有时候(很频繁,每天可能1〜2次)我的服务器不接收数据。我的客户端日志是这样的:
And it works. But... Sometimes (very infrequently, maybe 1 or 2 times per day) my server don't receive data. My client log looks like:
Written A
Written B
Written C
Written D
Written E
等。但是在服务器端,它看起来像:
and so on. But on the server side it looks like:
Received A
Received E
B,C没有接收D个数据记录,尽管事实是在客户端,它看起来像所有数据被发送,没有任何例外!
B,C,D data records were not received, despite of fact that on the client side it looks like all data was sent without any exceptions!
这样的差距可以是小(2-3分钟),这是不是很糟糕,但有时也可以是非常大的(1-2小时= 60-120次),它是真正为我的客户一个问题。
Such gaps can be small (2-3 minutes) which is not very bad, but sometimes they can be very big (1-2 hours = 60-120 cycles) and it is really a problem for my customers.
我真的不知道有什么可以是错误的。该数据似乎是由客户端被发送,但它从未到达在服务器端。我检查它也有一个代理。
I really have no idea what can be wrong. The data seems to be sent by client, but it never arrives on the server side. I've checked it also with a proxy.
我只有日志,我无法重现此问题(但它发生在我的客户,每天一个以上的时间),并在日志有时我看到连接异常而破SENDTO失败:ECONNRESET(连接由同行复位)。之后,该程序将关闭套接字,重新初始化它:
I have only logs and I can't reproduce this issue (but it happens to my customer more then one time every day) and in logs sometimes I see that the connection is broken with an Exception "sendto failed: ECONNRESET (Connection reset by peer)". After that the program closes the socket, reinitializes it:
// close
is.close();
os.close();
socket.close();
// reinitialize
initSocket();
和尝试,如上所述,再次写入数据。然后,我看到了问题:连接建立,写成功,但没有数据到达服务器
and tries to write the data again as described above. Then I see the problem: connection established, writing successful, but NO DATA arrived on the server!
可能是它是与ECONNRESET可能是没有,但我想提一提这个,因为可能是很重要的。
May be it has something to do with ECONNRESET may be not, but I want to mention this because may be it is important.
我会很感激的任何想法和建议。
I would be very grateful for any ideas and tips.
P.S。也许它起着一定的作用:客户端code被移动(这是在汽车)的Android移动设备上运行。互联网连接通过GPRS建立。
P.S. Maybe it plays some role: the client code runs on an Android mobile device which is moving (it is in a car). The internet connection is established through GPRS.
UPD:我可以重现它!至少部分地(客户端发送A,B,C,D,E和服务器只接收A)。它发生的每一次的话:
UPD: I can reproduce it! At least partially (the client send A,B,C,D,E and the server receives only A). It happens every time if:
-
建立连接,客户端读取和写入 - >确定
The connection is established, the client reads and writes -> OK
的连接丢失(我关掉我的无线路由器:)),我成了IOException异常,我关闭了流和插座 - >确定
The connection is lost (I turn off my WLAN router :)), I became IOException, I close the streams and socket -> OK
我把我的路由器,连接又回来了,我再次初始化套接字,程序执行的write()无异常,但没有数据......到达服务器。
I turn on my router, the connection is back, I initialize the socket again, the program executes write() without exceptions, but... no data arrives at the server.
顺便说一句,因为连接回来用()返回始终为0。
BTW since the connection is back again available() returns always 0.
这种奇怪的行为的原因是服务器端的一个未关闭套接字。我可以用小的客户端和服务器复制它。这两个由几行code,它执行以下操作:
The cause of this strange behavior was a not closed socket on the server side. I could reproduce it with small client and server. Both consist of couple of lines of code, which do the following:
- 连接到服务器
- 模拟死点(如关闭您的WiFi)
- 关闭套接字在客户端
- 请不要合上服务器端插座
- 在打开你的无线
- 建立从客户端的新连接
- 写数据到这个连接
瞧!客户端将数据写入没有任何错误,但服务器没有收到它...
Voila! The client writes data without any errors, but the server doesn't receive it...
但是,如果该服务器过于关闭套接字,那么服务器可以读取该数据。因此该解决方案应该是在服务器端在超时后关闭套接字。
But if the server closes the socket too, then the server can read this data. So the solution should be to close the socket after a timeout on the server side.
不幸的是在我的情况下,它是不可行的,因为服务器是一个专有的第三方软件。
Unfortunately in my case it is not viable, because the server is a proprietary third-party software.