我希望能找到有关我烦人问题的任何帮助。
我有一个带有c#
的java和客户端程序的TCP服务器程序 这两者之间的分组协议简单地由4字节长度组成。身体ASCII数据。问题是C#客户端面临FormatException,它来自解析在长度字节上失败。如果我从客户端查看错误,那么客户端正在尝试解析正文中不是长度标题的某个地方。 但显然,Server不会发送损坏的数据包。
同时,在服务器上,每当发生这种问题时,我都会发现一个Broken pipe错误。
不幸的是,此错误并非总是发生,并且无法重新创建问题情况。这让我很难找到这个问题的确切原因
请参阅下面的服务器端代码
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);
}
}
考虑到重建问题是不可能的,我猜这个问题来自多线程问题。但我找不到任何进一步的线索来解决这个问题。
如果你们需要更多信息来解决这个问题,请告诉我。
任何帮助都将非常感谢,提前感谢。
答案 0 :(得分:1)
关闭另一侧的连接会导致管道损坏。很可能C#
客户端有一个错误,导致格式异常导致它关闭连接,从而导致服务器端的管道损坏。请参阅what is the meaning of Broken pipe Exception?。
检查此读取的返回值:
byte[] bodyBuf = new byte[length];
reader.Read(bodyBuf, 0, length);
根据Microsoft文档BinaryReader.Read https://msdn.microsoft.com/en-us/library/ms143295%28v=vs.110%29.aspx
[返回值为]读入缓冲区的字节数。如果许多字节不可用,这可能小于请求的字节数,如果到达流的末尾,则可能为零。
如果读取的长度小于字节长度,则下次使用最后一条消息中间某处的数据解析长度。
答案 1 :(得分:0)
当客户端(浏览器)关闭连接时,会发生这些中断管道异常,但服务器(您的标记)继续尝试写入流。
当有人在浏览器中单击“后退”,“停止”等,并且在请求完成之前它与服务器断开连接时,通常会发生这种情况。有时,它可能会发生,例如,Content-Length标头不正确(并且浏览器将其值视为true)。
通常,这是一个非事件,没什么好担心的。但是如果你在开发环境中看到它们,当你知道你没有中断浏览器时,你可能会多挖一点以找出原因。
WLS服务器将尝试从Web容器中过滤掉日志中的这些异常,因为它是由客户端(浏览器)操作引起的,我们无法对其执行任何操作。但服务器并没有抓住所有这些。