[英]Broken pipe error communicating with Java server & C# client in multi thread env
我希望对我的旧烦恼问题有所帮助。
我有一个带有Java的TCP服务器程序和一个带有C#的客户端程序
两者之间的分组协议仅由4字节长度和主体ASCII数据组成。
问题是C#客户端遇到FormatException,这是由于解析长度字节失败而引起的。 如果我从客户端查看错误,则客户端正在尝试解析正文中某个不是长度标头的地方。 但是显然,服务器不会发送损坏的数据包。
同时,在服务器上,每当发生此类问题时,我都可以发现管道损坏的错误。
不幸的是,此错误并非总是会发生,并且无法重现问题情况。 这使我很难找到此问题的确切原因
请参阅以下服务器端代码
public class SimplifiedServer {
private Map<InetAddress, DataOutputStream> outMap;
private Map<InetAddress,DataInputStream> inMap;
protected void onAcceptNewClient(Socket client) {
DataOutputStream out = null;
DataInputStream in = null;
try {
out = new DataOutputStream(client.getOutputStream());
in = new DataInputStream(client.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
outMap.put(client.getInetAddress(), out);
inMap.put(client.getInetAddress(), in);
}
public void writeToAll(String packet) {
outMap.forEach((key, out) -> {
try {
byte[] body = packet.getBytes("UTF-8");
int len = body.length;
if (len > 9999) {
throw new IllegalArgumentException("packet length is longer than 10000, this try will be neglected");
}
String lenStr = String.format("%04d%s", len, packet);
byte[] obuf = lenStr.getBytes();
synchronized (out) {
out.write(obuf);
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
});
}
public void listenClient(Socket client) {
try {
DataOutputStream out = outMap.get(client.getInetAddress());
DataInputStream in = inMap.get(client.getInetAddress());
while (true) {
byte[] received = SimplePacketHandler.receiveLpControlerData(in);
byte[] lenBytes = new byte[4];
for( int i = 0 ; i < 4 ; i ++){
lenBytes[i] = in.readByte();
}
String lenString = new String(lenBytes);
int length = Integer.parseInt(lenString);
byte[] data = new byte[length];
for ( int i = 0 ; i < length ; i ++){
data[i] = in.readByte();
}
if ( data == null ){
System.out.println("NetWork error, closing socket :" + client.getInetAddress());
in.close();
out.close();
outMap.remove(client.getInetAddress());
inMap.remove(client.getInetAddress());
return;
}
doSomethingWithData(out, data);
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch ( Exception e ) {
e.printStackTrace();
} finally {
try {
System.out.println(client.getRemoteSocketAddress().toString() + " closing !!! ");
// remove stream handler from map
outMap.remove(client.getInetAddress());
inMap.remove(client.getInetAddress());
//close socket.
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这是客户端代码
public class ClientSide
{
public TcpClient client;
public String ip;
public int port;
public NetworkStream ns;
public BinaryWriter writer;
public BinaryReader reader;
public Boolean isConnected = false;
public System.Timers.Timer t;
public String lastPacketSucceeded = String.Empty;
public ClientSide(String ip, int port)
{
this.ip = ip;
this.port = port;
client = new TcpClient();
}
public bool connect()
{
try
{
client.Connect(ip, port);
}
catch (SocketException e)
{
Console.WriteLine(e.ToString());
return false;
}
Console.WriteLine("Connection Established");
reader = new BinaryReader(client.GetStream());
writer = new BinaryWriter(client.GetStream());
isConnected = true;
return true;
}
public void startListen()
{
Thread t = new Thread(new ThreadStart(listen));
t.Start();
}
public void listen()
{
byte[] buffer = new byte[4];
while (true)
{
try
{
reader.Read(buffer, 0, 4);
String len = Encoding.UTF8.GetString(buffer);
int length = Int32.Parse(len);
byte[] bodyBuf = new byte[length];
reader.Read(bodyBuf, 0, length);
String body = Encoding.UTF8.GetString(bodyBuf);
doSomethingWithBody(body);
}
catch (FormatException e)
{
Console.WriteLine(e.Message);
}
}
}
public void writeToServer(String bodyStr)
{
byte[] body = Encoding.UTF8.GetBytes(bodyStr);
int len = body.Length;
if (len > 10000)
{
Console.WriteLine("Send Abort:" + bodyStr);
}
len = len + 10000;
String lenStr = Convert.ToString(len);
lenStr = lenStr.Substring(1);
byte[] lengthHeader = Encoding.UTF8.GetBytes(lenStr);
String fullPacket = lenStr + bodyStr;
byte[] full = Encoding.UTF8.GetBytes(fullPacket);
try
{
writer.Write(full);
}
catch (Exception)
{
reader.Close();
writer.Close();
client.Close();
reader = null;
writer = null;
client = null;
Console.WriteLine("Send Fail" + fullPacket);
}
Console.WriteLine("Send complete " + fullPacket);
}
}
考虑到不可能重现问题,我猜这个问题是由于多线程问题引起的。 但我找不到解决此问题的任何其他线索。
如果您需要更多信息来解决此问题,请告诉我。
任何帮助将不胜感激,在此先感谢。
断开管道的另一端导致管道破裂。 C#
客户端很可能有一个错误,导致格式异常,这导致其关闭连接,并因此断开了服务器端的管道。 看看Broken pipe Exception是什么意思? 。
检查此读取的返回值:
byte[] bodyBuf = new byte[length];
reader.Read(bodyBuf, 0, length);
根据Microsoft BinaryReader文档。阅读https://msdn.microsoft.com/zh-cn/library/ms143295%28v=vs.110%29.aspx
[返回值为]读入缓冲区的字节数。 如果有许多字节不可用,则该数目可能小于所请求的字节数;如果到达流的末尾,则该数目可能为零。
如果读取的数据少于长度字节,则下一次它将使用最后一条消息中间某处的数据来解析长度。
当客户端(浏览器)关闭连接,但服务器(您的标记)继续尝试写入流时,会发生这些管道中断异常。
当有人在浏览器中单击“上一步”,“停止”等,并且在请求完成之前与服务器断开连接时,通常会发生这种情况。 有时可能会发生,因为例如Content-Length标头不正确(浏览器将其值设为true)。
通常,这是非事件,无需担心。 但是,如果您知道自己没有中断浏览器就在自己的开发环境中看到它们,那么您可能需要进一步研究以找出原因。
WLS服务器将尝试从Web容器中将这些异常从日志中筛选出来,因为这是由于客户端(浏览器)操作引起的,我们无法对此进行任何处理。 但是服务器无法捕获所有这些。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.