Winsock接收数据

时间:2015-02-08 13:44:53

标签: c# winsock

我正在尝试向服务器发送一个非常大的信息(大小为11000)并且遇到问题。信息未完整。

查看代码:

在我的服务器上,有一个循环。

    do
    {

        Tick = Environment.TickCount;

        Listen.AcceptClient();
        Listen.Update();
    }

Listen.update

    public static void UpdateClient(UserConnection client)
    {
        string data = null;
        Decoder utf8Decoder = Encoding.UTF8.GetDecoder();
       // byte[] buffer = new byte[client.TCPClient.Available];
            //try
            //{
                //client.TCPClient.GetStream().
            //    client.TCPClient.GetStream().Read(buffer, 0, buffer.Length);
            //}
            //catch
            //{
            //   int code = System.Runtime.InteropServices.Marshal.GetExceptionCode();
            //  Console.WriteLine("Erro Num: " + code);
            //}
            //data = Encoding.UTF8.GetString(buffer);
            //Console.WriteLine("Byte is: " + ReadFully(client.TCPClient.GetStream(), 0));
            Console.WriteLine("Iniciando");
            byte[] buffer = ReadFully(client.TCPClient.GetStream(), 0);
            int charCount = utf8Decoder.GetCharCount(buffer, 0, buffer.Length);
            Char[] chars = new Char[charCount];
            int charsDecodedCount = utf8Decoder.GetChars(buffer, 0, buffer.Length, chars, 0);

            foreach (Char c in chars)
            {
                data = data + String.Format("{0}", c);
            }

            int buffersize = buffer.Length;
            Console.WriteLine("Byte is: " + buffer.Length);


            Console.WriteLine("Data is: " + data);
            Console.WriteLine("Size is: " + data.Length);
            Server.Network.ReceiveData.SelectPacket(client.Index, data);
    }
    /// <summary>
    /// Reads data from a stream until the end is reached. The
    /// data is returned as a byte array. An IOException is
    /// thrown if any of the underlying IO calls fail.
    /// </summary>
    /// <param name="stream">The stream to read data from</param>
    /// <param name="initialLength">The initial buffer length</param>
    public static byte[] ReadFully(Stream stream, int initialLength)
    {
        // If we've been passed an unhelpful initial length, just
        // use 32K.
        if (initialLength < 1)
        {
            initialLength = 32768;
        }

        byte[] buffer = new byte[initialLength];
        int read = 0;

        int chunk;

        chunk = stream.Read(buffer, read, buffer.Length - read);

        checkreach:
            read += chunk;

            // If we've reached the end of our buffer, check to see if there's
            // any more information
            if (read == buffer.Length)
            {
                int nextByte = stream.ReadByte();
                // End of stream? If so, we're done
                if (nextByte == -1)
                {
                    return buffer;
                }
                // Nope. Resize the buffer, put in the byte we've just
                // read, and continue
                byte[] newBuffer = new byte[buffer.Length * 2];
                Array.Copy(buffer, newBuffer, buffer.Length);
                newBuffer[read] = (byte)nextByte;
                buffer = newBuffer;
                read++;
                goto checkreach;
            }

        // Buffer is now too big. Shrink it.
        byte[] ret = new byte[read];
        Array.Copy(buffer, ret, read);
        return ret;
    }

Listen.AcceptClient

    //Tem alguém querendo entrar na putaria? ;D
    if (listener.Pending())
    {
        //Adicionamos ele na lista
        Clients.Add(new UserConnection(listener.AcceptTcpClient(), Clients.Count()));

这是我的winsock服务器。

任何人都有提示或解决方案吗?

1 个答案:

答案 0 :(得分:0)

从这里开始:Winsock FAQ。它将解释您需要了解的一些事项,包括您不可能通过一次调用Read()来读取已发送的所有数据。每个单独的TCP程序都需要包含通过某种类型的循环接收数据的某个逻辑,并且在大多数情况下还需要逻辑来解释所接收的数据以识别所接收数据的各个元素之间的边界(例如逻辑消息等......唯一的例外是当应用程序协议规定从连接到闭包的整个传输代表一个“单元”时,在这种情况下唯一重要的边界是流的结尾。)

另外(为了解决这里包含的一小部分代码中的一些错误):

  • 使用TcpClient.Available; 正确的代码中不需要它。
  • 使用Marshal.GetExceptionCode()检索托管例外的异常信息
  • 当您的值已经是Convert.ToInt32() 的实例时,
  • 使用System.Int32。更一般地说,在简单的强制转换完成同样的事情的情况下,根本不要使用Convert(即使这里不需要演员,但我可以从代码中看出你的一般习惯是什么......你应该打破这种习惯。)
  • 不要只是忽略异常。要么实际上处理它们,要么让它们传播到调用堆栈。如果UpdateClient()方法抛出异常,则Read()方法中的其余代码无法正常工作,但无论如何都要继续执行。
  • Flush()对象上使用NetworkStream方法。它什么都不做(只有因为Stream类需要它才有效)。
  • 执行使用Stream.ReadAsync()而不是将线程专用于每个连接
  • 通过包含异常类型和变量来接受异常对象引用来捕获异常
  • 使用持久性 Decoder对象来解码UTF8编码的文本(或任何其他可变字节长度的文本编码),以便字符的编码表示跨越多个接收的缓冲区,文本仍然正确解码。

最后:


附录:

  • 不要使用goto声明。使用适当的循环(例如while)。如果您使用了正确的循环,您可能已经避免了代码中的错误,即您无法回到实际的Read()调用。
  • 不要期望Read()方法填充您传递的缓冲区。不仅(正如我上面已经提到的)不能保证所有发送的数据都会在一次调用中返回Read(),因此无法保证传递给Read()的整个缓冲区都将在Read()返回之前填写。
  • 不要一次读取一个字节。这是杀死性能和/或引入错误的最可靠方法之一。在你自己的例子中,我没有看到任何明显的错误 - 你只是(打算)在寻找更多数据时读取单个字节然后(打算)返回读取更大的缓冲区 - 但它不是必需的(只是尝试通常读取更多数据......在代码中没有特殊情况可以获得相同的信息,这可能导致错误,并且在任何情况下都会使代码更难理解。)
  • 查看网络代码的其他示例和教程。重新发明轮子最终可能会导致一个很好的解决方案,但可能性很低,而且比跟随其他人的好榜样要费时且容易出错。

我将重申:请阅读Winsock常见问题解答。它有很多有价值的信息,每个想要编写网络代码的人都需要知道。

我还要重申:没有COMPLETE代码示例,你无法得到准确的答案。