Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Thrift TSimpleServer在多次成功请求后变得无响应_Java_.net_Tcp_Thrift - Fatal编程技术网

Java Thrift TSimpleServer在多次成功请求后变得无响应

Java Thrift TSimpleServer在多次成功请求后变得无响应,java,.net,tcp,thrift,Java,.net,Tcp,Thrift,我有一个在Linux上运行的Java应用程序提供的Thrift API。我正在使用.NET客户端连接到API并执行操作 对服务的前几个调用可以正常工作,没有错误,但随后(似乎是随机的)一个调用将“挂起”。如果我强制退出客户端并尝试重新连接,服务将再次挂起,或者我的客户端出现以下错误: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote

我有一个在Linux上运行的Java应用程序提供的Thrift API。我正在使用.NET客户端连接到API并执行操作

对服务的前几个调用可以正常工作,没有错误,但随后(似乎是随机的)一个调用将“挂起”。如果我强制退出客户端并尝试重新连接,服务将再次挂起,或者我的客户端出现以下错误:

Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
   at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
   at Thrift.Transport.TStreamTransport.Read(Byte[] buf, Int32 off, Int32 len) 
   (etc.)
当我使用JConsole获取线程转储时,服务器处于
accept()

请注意,我们使用的是采用显式主机名或IP地址的
TServerTransport
构造函数。我怀疑应该将其更改为只指定端口的构造函数(最终绑定到
InetAddress.anyLocalAddress()
)。或者,我想我可以将服务配置为绑定到“通配符”地址(“0.0.0.0”)

我应该提到的是,这项服务不是在开放的互联网上托管的。它托管在一个专用网络中,我正在使用SSH隧道来访问它。因此,服务绑定到的主机名不会在本地网络中解析(尽管我可以通过隧道进行初始连接)。我想知道这是不是类似于

是否有技术上的解释(如果这是一个常见问题)或我可以采取的其他故障排除步骤

更新

今天也有同样的问题,但这次
jstack
显示Thrift服务器永远阻止从输入流读取:

"Thread-1" prio=10 tid=0x00002aaad43fc000 nid=0x60b3 runnable [0x0000000041741000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
            at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:127)
        at org.apache.thrift.transport.TTransport.readAll(TTransport.java:84)
        at org.apache.thrift.protocol.TBinaryProtocol.readAll(TBinaryProtocol.java:378)
        at org.apache.thrift.protocol.TBinaryProtocol.readI32(TBinaryProtocol.java:297)
        at org.apache.thrift.protocol.TBinaryProtocol.readMessageBegin(TBinaryProtocol.java:204)
        at org.apache.thrift.TBaseProcessor.process(TBaseProcessor.java:22)
        at org.apache.thrift.server.TSimpleServer.serve(TSimpleServer.java:70)

因此,我们需要在
TServerSocket
构造函数中设置“客户端超时”。但是,当阻止堆栈跟踪中的
accept()

时,为什么会导致应用程序也拒绝连接呢

用于测试的简单单线程服务器

也许你想用的是


最有可能发生的情况是,TSimpleServer的单个线程被阻塞,等待死机响应或超时。由于TSimpleServer是单线程的,因此没有线程可用于处理其他请求。

我有一些建议。您提到,对服务器的最初几次调用都是有效的,然后出现挂起。这是个线索。发生这种情况的一种情况是,客户端未将字节完全发送到服务器。我不熟悉TSimpleServer,但我假设它侦听端口,并且有一些二进制协议,并且希望任何客户机都能使用该协议与它通信。您的.net客户端正在通过发送字节与此服务器通信。如果它没有正确地刷新其输出缓冲区,那么它可能没有将所有字节发送到服务器,从而挂起服务器

在Java中,这可能发生在客户端,如下所示:

BufferedOutputStream stream = new BufferedOutputStream(socket.getOutputstream()) //get the socket stream to write 
stream.write(content);//write everything that needs to be written 
stream.flush();//if flush() is not called, could result in server getting incomplete packets resulting in hangs!!!
建议:

a) 检查你的.net客户端代码。查看实际与服务器通信的代码的任何部分是否正确调用了等效的flush()或cleanup方法。 注意:我从他们的文档中看到,他们的传输层定义了一个flush()。您应该扫描.net代码,看看它是否使用了传输方法

b) 为了进一步调试,您可以尝试编写一个模拟.net客户端的小型Java客户端。在linux机器上运行java客户端(与TSimpleServer运行的机器相同)。看看是否会引起同样的问题。如果确实如此,您可以调试java客户机并找到根本原因。如果没有,那么您可以在.net客户端运行的地方运行它,看看是否有任何问题,然后从那里着手

编辑:c)我可以在Java中看到一个示例thrift客户端代码: 我注意到 transport.open(); //做一些代码 transport.close();
正如a)中所建议的,您可以浏览.net客户端代码,查看是否在完成时调用了传输方法flush()和close()

将储蓄服务绑定到通配符地址(“0.0.0.0”)解决了问题,不再挂起

使用多线程服务器将使应用程序更具响应性,但仍会导致挂起/不完整的请求


如果有人偶然发现了这个问题,并且能够提供一个更完整的解释,以及它与Java RMI TCP回调问题(我在问题中链接到了这个问题)的关系,请投你一票。

我有一个类似的c++服务器/客户机环境

c++客户端调用一个方法(attributeDefinitionsAliases)并等待响应

c++服务器开始写入套接字,但锁定。线鲨捕获:

关闭c++服务器上的c++客户端后,会出现异常:

Thrift内部消息:TSocket::write_partial()send():errno=10054

Thrift内部消息:TConnectedClient已死亡:write()send():errno=10054

编辑1:
这不是节俭的问题。服务器启动/启动的方式似乎有问题。我有一个应用程序(launcher app),它使用QProcess()启动/启动服务器,使用popen运行良好

可能是相关(或相同)问题?啊,但是为什么即使在客户端被终止并且stacktrace处于“accept()”状态之后,它仍会继续挂起/拒绝连接?当您无法连接时,您确定在accept上被阻止了吗?如果没有连接,则在接受时阻塞是正常的,您可能在Socket.read调用超时后获取了堆栈跟踪。第二个堆栈跟踪与等待客户端的单线程服务器一致。应用程序处于两种不同的状态:挂起
读取
和拒绝所有请求,而stacktrace具有
接受
。我担心在赏金到期之前无法测试您提出的解决方案。我希望对我提供的信息进行更详细的技术分析。但是,如果没有其他人提供更好的服务,我可能会接受你的回答
"Thread-1" prio=10 tid=0x00002aaad43fc000 nid=0x60b3 runnable [0x0000000041741000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
            at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:127)
        at org.apache.thrift.transport.TTransport.readAll(TTransport.java:84)
        at org.apache.thrift.protocol.TBinaryProtocol.readAll(TBinaryProtocol.java:378)
        at org.apache.thrift.protocol.TBinaryProtocol.readI32(TBinaryProtocol.java:297)
        at org.apache.thrift.protocol.TBinaryProtocol.readMessageBegin(TBinaryProtocol.java:204)
        at org.apache.thrift.TBaseProcessor.process(TBaseProcessor.java:22)
        at org.apache.thrift.server.TSimpleServer.serve(TSimpleServer.java:70)
BufferedOutputStream stream = new BufferedOutputStream(socket.getOutputstream()) //get the socket stream to write 
stream.write(content);//write everything that needs to be written 
stream.flush();//if flush() is not called, could result in server getting incomplete packets resulting in hangs!!!