【问题标题】:Sending large strings through TCP - Windows Phone通过 TCP 发送大字符串 - Windows Phone
【发布时间】:2013-06-28 05:15:23
【问题描述】:

我在Windows Phone上开发了一个简单的TCP客户端,如图here on MSDN

这是按预期工作的。

现在,我想通过这个客户端发送非常大的 Base64 字符串(用于传输图像)。 但是,当我尝试从该客户端发送 Base64 字符串时,我在服务器上只收到了部分字符串,因此我无法在服务器上生成整个图像。

接收字符串的服务器端代码为:(Edited)

            IPAddress ipAd = IPAddress.Any;

            Console.Write("Port No. (leave blank for port 8001): ");
            string port;
            port = Console.ReadLine();

            if (port == "")
                port = "8001";

            /* Initializes the Listener */
            TcpListener myList = new TcpListener(ipAd, int.Parse(port));

            /* Start Listeneting at the specified port */
            myList.Start();                

            Console.WriteLine("\nThe server is running at port " + port);
            Console.WriteLine("The local End point is  :" +
                              myList.LocalEndpoint);
            Console.WriteLine("\nWaiting for a connection.....");

            Socket s = myList.AcceptSocket();
            Console.WriteLine("\nConnection accepted from " + s.RemoteEndPoint);

            byte[] b = new byte[5 * 1024 * 1024]; // BIG SIZE for byte array, is this correct?
            String message = String.Empty;

            int k = s.Receive(b);
            Console.WriteLine("\nRecieved...");
            for (int i = 0; i < k; i++)
            {
                message += Convert.ToChar(b[i]);
                Console.Write(Convert.ToChar(b[i]));
            }

            System.IO.File.WriteAllText(@"Message.txt", message);  // write it to a file

            ASCIIEncoding asen = new ASCIIEncoding();
            s.Send(asen.GetBytes("The string was recieved by the server."));
            Console.WriteLine("\n\nSent Acknowledgement");
            /* clean up */
            s.Close();
            myList.Stop();

我真的被困在这里了。 请帮帮我。

我认为问题出在客户端而不是服务器。 请帮助我。

我在客户端使用的类可以在上面提到的MSDN article找到。

PS:我已经尝试增加类中TIMEOUT_MILLISECONDSMAX_BUFFER_SIZE的值。但这并没有帮助。

更新:

这是一些客户端代码 (look here on MSDN for reference):

        // Make sure we can perform this action with valid data
        if (ValidateRemoteHost() && ValidateInput())
        {
            // Instantiate the SocketClient
            SocketClient client = new SocketClient();

            // Attempt to connect to the echo server
            Log(String.Format("Connecting to server '{0}' over port {1} (echo) ...", txtRemoteHost.Text, ECHO_PORT), true);
            string result = client.Connect(txtRemoteHost.Text, ECHO_PORT);
            Log(result, false);

            byte[] bytearray = null;

            // Attempt to send our message to be echoed to the echo server
            Log(String.Format("Sending '{0}' to server ...", txtInput.Text), true);
            if (checkBox1.IsChecked == true)  // this checkbox is for image selection
            {


                // This is the part where we send images


                using (MemoryStream ms = new MemoryStream())
                {
                    WriteableBitmap wbitmp = new WriteableBitmap((BitmapImage)image1.Source);

                    wbitmp.SaveJpeg(ms, (int)wbitmp.PixelWidth, (int)wbitmp.PixelHeight, 0, 10);
                    bytearray = ms.ToArray();
                    string str = Convert.ToBase64String(bytearray);                        

                    result = client.Send(str);
                    System.Diagnostics.Debug.WriteLine("\n\nMessge sent:\n\n" + str + "\n\n");
                }                                        
            }
            else
            {
                result = client.Send(txtInput.Text);
            }

            Log(result, false);

            // Receive a response from the server
            Log("Requesting Receive ...", true);
            result = client.Receive();
            Log(result, false);

            // Close the socket connection explicitly
            client.Close();
        }

【问题讨论】:

  • 客户端能否发送大的 Base64 字符串?
  • 你确定你没有在一切都完成之前关闭客户端的套接字吗?我建议您使用 Wireshark 之类的工具来查看实际发送的数据。
  • 如果你认为客户端有问题,那么客户端的代码在哪里?
  • Jon 很可能是正确的 - TCP 是“礼貌”协议,因此“即发即弃”不像在 UDP 中那样工作,并且断开连接事件可能会超过网络缓冲区。正确的方法是有一个协议,服务器向客户端确认已收到所有数据。在移动世界中,对协议进行大小健全性检查也可能会有所帮助。
  • TCP 通常会(尝试)确保在完全处理断开连接之前所有数据都通过(除非尚未完成接收数据的系统尝试发送)

标签: c# windows-phone-7 tcp base64 tcpclient


【解决方案1】:
                    while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0)
                    {
                        Fs.Write(RecData, 0, RecBytes);
                        totalrecbytes += RecBytes;
                    }

编辑:现在该部分代码已缩减为仅

        int k = s.Receive(b);

很糟糕:它假设所有数据一次完美发送,这不是网络的工作原理。

两种选择:

  • 在字符串的开头,包括它应该多长。
  • 在字符串的末尾,有一个结束符号(可能是 null),它不会出现在消息中的其他任何地方

然后,while 循环应该继续进行,直到找到整个长度或找到结束符号。

(此外,如果可以避免发送 Base64 是一个坏主意。为什么不作为原始字节流发送?)

[ED:这部分不再相关](另外,为什么服务器选择保存文件的位置[并延迟一切直到服务器做出选择] - 客户端应该在开始时指出保存位置,然后服务器只是对其进行健全性检查。[除非你有充分的理由不这样做])

编辑:我所说的快速简单的实现:

此服务器代码

        int k = s.Receive(b);
        Console.WriteLine("\nRecieved...");
        for (int i = 0; i < k; i++)
        {
            message += Convert.ToChar(b[i]);
            Console.Write(Convert.ToChar(b[i]));
        }

改成

        while (true)
        {
            int k = s.Receive(b);
            Console.WriteLine("\nRecieved...");
            for (int i = 0; i < k; i++)
            {
                char bc = Convert.ToChar(b[i]); // This is a very wrong way of doing this but it works I guess meh.
                if (bc == ' ')
                { // You've struck the end! Get out of this infinite loop!
                    goto endmyloop;
                }
                message += bc;
                Console.Write(bc);
            }
        }
        endmyloop:

这段客户端代码

                result = client.Send(str);

改成

                result = client.Send(str + " ");

-- Base64 中永远不能有空格,所以这将用于标记结束。

请注意,如果客户端出错(并且由于某种奇怪的原因没有在末尾发送空格),此代码将永远被困在 while 循环中(零 CPU 使用无限等待)

【讨论】:

  • 非常感谢您的帮助。我尝试使用 Windows Simple TCP Services 作为服务器(而不是我的),它运行良好。因此,很明显问题出在服务器上。但是,你能帮我逐个字符地读取字符串,而不是使用int k = s.Receive(b),这样我就可以循环接收内容,并在接收到字符串结尾字符(手动附加)时打破循环。
  • 您只需对当前代码进行一些小的编辑即可实现它。请参阅我的编辑上面的答案。老实说,您的整个现有代码和其中包含的非常基本的想法都存在严重缺陷......但是在这里试图解释这一切是没有意义的。继续练习 C# 和阅读教程!
  • 我是 C# 网络的新手,我没有太多经验,所以我可能会使用不好的做法!好吧,无论如何,我已经尝试过您在此处所说的方法,但是没有用。它在无限循环中运行(并且空间是通过客户端发送的,我使用 Simple TCP 服务作为服务器对其进行了验证)。我认为问题的出现是因为整个流仅在以下位置获取一次:int k = s.Receive(b); 并且我们每次都在无限循环中接收相同的内容(截断的字符串),对吗?
  • @ShrayanshSharma - 可以肯定的是,您可以使用 OP 的代码与我编写的确切代码相结合来插入它,而无需自己更改它,并告诉我这是怎么回事? -- 还假设TcpListener.Receive 与底层Socket.Receive 一样,它应该只返回相同的文本块两次,相同的文本块被发送两次。
  • 我已尝试按原样使用您的代码,而无需进行任何更改。但它在无限循环中运行,可能是因为我们只在一个语句中接收到它:int k = s.Receive(b);。下面的while 循环只是为了读取我们存储在字节数组中的内容(如果你看到了,我们只是在循环中读取字节数组)。所以问题出在声明中:int k = s.Receive(b);。不是在一个语句中接收所有内容,而是可以逐个字符地接收它吗?
猜你喜欢
  • 2014-01-01
  • 1970-01-01
  • 2020-02-17
  • 2013-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多