C#联网:服务器在接收到超过65535字节后挂起
更新: 由于Stackoverflow上管理员的问题,我在MSDN论坛上发布了一个非常精简的版本。下面的文本使用了MyNetworking.dll,但这不是问题所在。这是一个非常精简的客户机-服务器问题,问题也完全相同。请随意试用=) /UPDATE 所以,我有一个奇怪的错误 通常,我们有一个DLL来处理我们的网络。让我们调用C#联网:服务器在接收到超过65535字节后挂起,c#,networking,C#,Networking,更新: 由于Stackoverflow上管理员的问题,我在MSDN论坛上发布了一个非常精简的版本。下面的文本使用了MyNetworking.dll,但这不是问题所在。这是一个非常精简的客户机-服务器问题,问题也完全相同。请随意试用=) /UPDATE 所以,我有一个奇怪的错误 通常,我们有一个DLL来处理我们的网络。让我们调用MyNetworking.dll。我们在服务器和客户机中随处使用它,并且已经使用了5年。到现在为止,我还没有遇到任何问题 我有一个“XMLPoller”,它从MySQL数据
MyNetworking.dll
。我们在服务器和客户机中随处使用它,并且已经使用了5年。到现在为止,我还没有遇到任何问题
我有一个“XMLPoller”,它从MySQL数据库中读取XML,将其序列化为byte[]数组,并通过网络发送。这些特定的XML消息是627字节的序列化形式
XMLPoller连接到“远程服务器”(恰好是本地主机)上的一个端口并发送数据包,一次发送一个数据包。恰好在数据包nbr 105处,连接关闭。从XMLPoller发送104个数据包,并由服务器接收。104 x 627=65208字节。但是数据包105,当发送的总字节数为65835时,连接因以下错误而关闭:
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
这是服务器上的错误。但是,我已经使用了XMLPoller(客户端),我看到当最后627个字节被发送时(因此发送到65835个字节),我在客户端上没有看到任何错误,发送过程中没有问题
瑞典时间20:15更新
当我再调试一点时,客户端也会出现此错误:
Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.
我想我已经确认了客户端中存在错误。我正在逐步检查代码,在服务器上捕获任何异常之前,我会在客户端上获得一个异常,如上所述。
/结束更新
在我看来,服务器从未接收到它,因此出现了上面的错误。由于客户端上发生了某些事情,服务器关闭了连接。但是,客户端上的错误在TCPInput中;由于某种原因,读取数据的流已死亡
我没有在MyNetworking.dll中缓冲任何内容
当我在套接字(服务器上)上获得新连接时,我执行以下代码:
public void setConnected(Socket thisClient)
{
NetworkStream stream = new NetworkStream(thisClient);
socket = thisClient;
output = new TCPOutput(stream, outputHandler,this);
remoteIP = this.socket.RemoteEndPoint.ToString();
changeState(State.Connected);
try
{
stream.BeginRead(inputBuffer, 0, 5000, new AsyncCallback(OnDataReceived), null);
}
catch (Exception e)
{
this.disconnect();
}
}
然后是OnDataReceived
方法(实际接收数据的位置):
现在我有点不知道发生了什么。。。有什么想法吗
更新1:
用于发送数据的客户端代码:
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
更新2
我尝试刷新来自客户端的传出流-无效
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
outputStream.Flush();
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
更新3:根据请求发布更多代码
我知道,这个代码很旧,不是世界上最漂亮的。但5年来它一直运行良好,因此=)
ClientHandler.cs
(实际客户端用于发送等的内容)
这个数字(“因此发送到65835字节”)神奇地接近于2^16-1
(65535)--看起来就像只发送了一个数据包
(我假设只是更大的尺寸让事情变得更糟!——这是可以可靠测试的。)
我怀疑(在库中)使用了一个无符号16位变量,您需要更大范围的变量。也许您可以定期“清空”库的内部,或者在多个连接中执行该操作?(好的,只是想抛出一些“快速黑客”的想法:-)问题在于您的另一个代码,即“客户端”。它在发送所有“数据包”后关闭连接。您必须等待,直到服务器收到所有这些文件。除了明确协商之外,还有一种简单的方法,就是等待服务器关闭连接。因此,在与我的犯罪搭档进行了大量测试和讨论后,我们发现,问题不再使用端口21,而是以端口22为例,问题消失了
我不知道它为什么会这样,但它确实…你的帖子给我提出了问题。比如,为什么要为这项服务选择知名的端口?我不相信巧合,我怀疑你使用的“犯罪伙伴”这个词可能比我想联系的更真实
然后,我还想知道为什么您假设一个Windows bug而不是MyNetowrking.dll中的bug。当然,你已经用了五年了。但是它还没有达到微软提供的代码的审查级别。你能给我们看一下客户端代码吗?更新了上面的我的文本=)事实上,现在。不完全是。不过我已经考虑过了。但这似乎很奇怪,因为我们在其他客户端中使用相同的代码,可以轻松地传输大量mb的数据,而无需关闭连接。。。但无论如何我现在都会尝试。请显示完整的客户端代码。全班同学。错误表明客户端已关闭连接。@crassy不,刷新没有帮助(请参阅更新的帖子)嗯,我不太确定。我已经更新了上面的文字。正如您所看到的,发送代码非常简单。它获取字节数组并写入输出流。我已经通过了那个密码,没有例外。它在结尾处返回“true”…有很多片段,但它们没有显示连接是如何关闭的。您收到的异常抱怨连接关闭过快。更新了上面的文本。我现在看到客户机与服务器收到相同的错误:“无法从传输连接读取数据:已建立的连接被主机中的软件中止。”因此,更新了文本。我想我很确定是客户惹我。Se更新了上面的“20:15”。是的,确切地说=)它肯定与65536有关。这就是为什么我在课文中指出这一点。但是所有使用的代码现在都显示出来了(客户端也是),并且没有找到Int16或类似的65535/65536。不过,我会尝试在一个包中发送65535,如果有效的话。。。嗯,因为没有好的理由,他们结束了关于同一主题的另一个问题,我可能会在这里问:这是Win/.NET中的一个bug吗?有人听说过t吗
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
outputStream.Flush();
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace tWorks.tNetworking.tNetworkingCF
{
/// <summary>
/// Summary description for connectionHandler.
/// </summary>
public class ClientHandler
{
#region Fields (17)
string address;
Connector connector;
DataHandler dataHandler;
int id;
TCPInput input;
int interval;
string localAddress;
IPEndPoint localPoint;
int localPort;
NetworkStream outputStream;
public TTCPClientInterface parent;
int port;
tWorks.tNetworking.Protocol.Protocol protocol;
bool reconnect;
string remoteIP;
Socket socket;
public State state;
#endregion Fields
#region Enums (1)
public enum State {Disconnected,Connecting,Connected}
#endregion Enums
#region Constructors (4)
public ClientHandler(int id, TTCPClientInterface parent, Socket socket, tWorks.tNetworking.Protocol.Protocol protocol)
{
this.id=id;
this.parent = parent;
this.protocol = protocol;
dataHandler = new DataHandler(protocol, this);
setConnected(socket);
}
public ClientHandler(int id, TTCPClientInterface parent, Protocol.Protocol protocol)
{
this.id=id;
this.parent = parent;
this.protocol = protocol;
dataHandler = new DataHandler(protocol, this);
state = State.Disconnected;
}
public ClientHandler(int id, TTCPClientInterface parent, Socket socket)
{
this.id=id;
this.parent = parent;
setConnected(socket);
}
public ClientHandler(int id, TTCPClientInterface parent)
{
this.id=id;
this.parent = parent;
this.protocol = null;
changeState(State.Disconnected);
}
#endregion Constructors
#region Delegates and Events (4)
// Delegates (2)
public delegate void ConnectionLostDelegate(string message);
public delegate void exceptionDelegate(Exception ex);
// Events (2)
public event exceptionDelegate ConnectionFailed;
public event ConnectionLostDelegate ConnectionLostEvent;
#endregion Delegates and Events
#region Methods (17)
// Public Methods (16)
public void connect(string address, int port, int retryInterval, bool reestablish)
{
System.Random rand = new Random();
localPort = rand.Next(40000, 60000);
IPAddress localIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0]; // new IPAddress(Dns.GetHostByName(Dns.GetHostName()).AddressList[0].Address);
connect(address, port, retryInterval, reestablish, localIP.ToString(), localPort);
}
/// <summary>
/// Will connect to the address and port specified. If connection failed a new attempt will be made according to the Interval parameter.
/// If connection is lost attempts to reastablish it will be made if Reestablish is set to true.
/// </summary>
/// <param name="address"></param>
/// <param name="port"></param>
/// <param name="retryInterval"></param>
/// <param name="reestablish"></param>
public void connect(string address, int port, int retryInterval, bool reestablish, string localAddress, int localPort)
{
this.reconnect = reestablish;
this.address = address;
this.port = port;
this.interval = retryInterval;
this.localAddress = localAddress;
this.localPort = localPort;
changeState(State.Connecting);
connector = new Connector(address, port, this, interval, localPoint, reestablish);
connector.Connect();
}
public void disconnect()
{
reconnect = false;
if (connector != null)
{
connector.stopConnecting();
}
setDisconnected();
}
public void dispose()
{
}
public void failedConnect(Exception e)
{
if (ConnectionFailed != null)
ConnectionFailed(e);
}
public int getID()
{
return this.id;
}
public string getIP()
{
return remoteIP;
}
public bool isConnected()
{
return this.state == State.Connected;
}
public void outDataLog(int nbrBytes)
{
parent.outDataLog(nbrBytes, id);
}
public void preProcessMessage(byte[] data)
{
//data = Crypto.Decrypt("a1s2d3", data);
if(protocol != null)
dataHandler.addData(data);
else
processMessage(data);
}
public void processMessage(byte[] data)
{
parent.processMessage(data,this);
}
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
outputStream.Flush();
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
public void setConnected(Socket thisClient)
{
socket = thisClient;
outputStream = new NetworkStream(thisClient);
input = new TCPInput(outputStream, this);
remoteIP = this.socket.RemoteEndPoint.ToString();
changeState(State.Connected);
}
public void setDisconnected()
{
try
{
if (this.state == State.Connected)
{
changeState(State.Disconnected);
//socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}
catch { }
if (reconnect)
this.connect(address, port, interval, true, localAddress, localPort);
}
public void stopConnect()
{
connector.stopConnecting();
changeState(State.Disconnected);
}
public override string ToString()
{
string returnString = "(D)";
if(this.state == State.Connected)
returnString = this.getIP();
return returnString;
}
// Private Methods (1)
private void changeState(State state)
{
if (this.state == State.Connected && state == State.Disconnected)
{
if (ConnectionLostEvent != null)
ConnectionLostEvent("Uppkoppling bröts.");
}
this.state = state;
parent.connStateChange(this);
}
#endregion Methods
}
}
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace tWorks.tNetworking.tNetworkingCF
{
public class TCPInput
{
NetworkStream stream;
ClientHandler client;
public TCPInput(NetworkStream nS, ClientHandler client)
{
stream = nS;
this.client = client;
Thread t = new Thread(new ThreadStart(run));
t.IsBackground = true;
t.Name = "TCPInput";
t.Start();
}
public void run()
{
bool continueRead = true;
byte[] readBuffer = new byte[32768];
byte[] receivedBuffer = null;
int nbrBytesRead = 0;
int receivedBufferPos = 0;
while(continueRead)
{
try
{
nbrBytesRead = 0;
nbrBytesRead = stream.Read(readBuffer, 0, 10000);
receivedBuffer = new byte[nbrBytesRead];
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("TCPInput> Exception when stream.Read: " + e.ToString());
continueRead = false;
}
if(nbrBytesRead > 0)
{
try
{
Array.Copy(readBuffer, 0, receivedBuffer, receivedBufferPos, nbrBytesRead);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("TCPInput> Exception when Array.Copy: " + e.ToString());
continueRead = false;
}
client.preProcessMessage(receivedBuffer);
}
else
{
// *** I can break here, the nbrOfBytes read is 0 when this whole thing explodes =)
System.Diagnostics.Debug.WriteLine("TCPInput> Number of bytes read == 0! Setting continueRead = false");
continueRead = false;
}
}
client.setDisconnected();
}
}
}