C#联网:服务器在接收到超过65535字节后挂起

C#联网:服务器在接收到超过65535字节后挂起,c#,networking,C#,Networking,更新: 由于Stackoverflow上管理员的问题,我在MSDN论坛上发布了一个非常精简的版本。下面的文本使用了MyNetworking.dll,但这不是问题所在。这是一个非常精简的客户机-服务器问题,问题也完全相同。请随意试用=) /UPDATE 所以,我有一个奇怪的错误 通常,我们有一个DLL来处理我们的网络。让我们调用MyNetworking.dll。我们在服务器和客户机中随处使用它,并且已经使用了5年。到现在为止,我还没有遇到任何问题 我有一个“XMLPoller”,它从MySQL数据

更新: 由于Stackoverflow上管理员的问题,我在MSDN论坛上发布了一个非常精简的版本。下面的文本使用了MyNetworking.dll,但这不是问题所在。这是一个非常精简的客户机-服务器问题,问题也完全相同。请随意试用=) /UPDATE

所以,我有一个奇怪的错误

通常,我们有一个DLL来处理我们的网络。让我们调用
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();
        }
    }
}