BinaryReader中是否有自动字节顺序检测

时间:2016-10-26 16:38:39

标签: c# networking bitmap

我正在开发一个客户端,它使用一个非常简单的协议通过TCP连接生成和传输位图:

  • [步骤1]以Int64
  • 的形式发送文件大小为n的字节
  • [步骤2]发送代表Bitmap-Data的n个字节

为了在开发过程中帮助我,我实现了一个等待连接的简单服务器,在客户端使用随机生成的文件名发送并将其存储在HDD上时接受文件

using System;
using System.Text;
using System.IO;
using System.Net.Sockets;

namespace SimplePictureReceiverServer
{
    class Program
    {
        private static Int32 PORT = -1;
        private static String DirSaveTo = null;

        static void Main(string[] args)
        {
            // Ensuring that required parameters have been provided
            if (args.Length < 2) { ShowUsage("Parameter-Count"); return; }
            if (!Int32.TryParse(args[0], out PORT)) { ShowUsage("<port>"); return; }
            if (!Directory.Exists(args[1])) { ShowUsage("<dir>"); return; }

            PORT = Int32.Parse(args[0]);
            DirSaveTo = args[1];

            // Setting up the Server on <127.0.0.1>:<PORT>
            TcpClient c = null; NetworkStream s;
            TcpListener l = new TcpListener(System.Net.IPAddress.Loopback, PORT); 
            l.Start();

            while(true)
            {
                // Waiting for a Client to connect
                Console.Write("Waiting ... ");  
                c = l.AcceptTcpClient();
                s = c.GetStream();
                Console.WriteLine("Ok");

                // Handle the client
                try
                {
                    using (BinaryReader r = new BinaryReader(s, Encoding.Unicode))
                    {
                        HandleClient(r);
                    }
                }
                catch(Exception e)
                {
                    Console.WriteLine("Client disconnected (" + e.Message + ")");
                    Console.WriteLine();
                }
            }
        }

        private static void ShowUsage(String s)
        {
            Console.WriteLine("Problem with " + s);
            Console.WriteLine();
            Console.WriteLine("USAGE \t program.exe <port> <dir>");
            Console.WriteLine("<port> : Port to listen to when waiting for connections");
            Console.WriteLine("<dir>  : Directory to store received pictures at. The directory must exist");
            Console.WriteLine();
            Console.WriteLine("Press [ENTER]");
            Console.ReadLine();
        }
        private static void HandleClient(BinaryReader r)
        {
            const Int32 BUF_SIZE = 10 * 1024;
            Int32 cntPicutresReceived = 0; StringBuilder b = new StringBuilder();

            Random rnd = new Random();
            Byte[] buf;

            Int32 bytesLeftToRead;

            while (true)
            {
                using (MemoryStream m = new MemoryStream())
                {
                    // Reading picture size and picture from stream
                    bytesLeftToRead = Convert.ToInt32(r.ReadInt64());               // Reading size as Int32
                                                                                    // Little/ Big Endian - Consider !

                    Console.WriteLine("Expected filesize is " + bytesLeftToRead.ToString("#,##0") + " Bytes");

                    while (bytesLeftToRead > 0)                                      // Reading the picture
                    {
                        buf = r.ReadBytes(Math.Min(BUF_SIZE, bytesLeftToRead));
                        m.Write(buf, 0, buf.Length);

                        bytesLeftToRead = bytesLeftToRead - buf.Length;
                    }

                    // Storing picture on HDD with a fancy filename created in the StringBuilder
                    m.Seek(0L, SeekOrigin.Begin);

                    b.Clear();
                    b.Append((++cntPicutresReceived).ToString("0000"));
                    b.Append("__");
                    b.Append(rnd.Next(Int32.MaxValue).ToString("X"));
                    b.Append(".bmp");

                    using (FileStream f = new FileStream(Path.Combine(DirSaveTo, b.ToString()), FileMode.Create))
                    {
                        m.CopyTo(f);
                    }

                    Console.WriteLine("Image saved at '" + Path.Combine(DirSaveTo, b.ToString()) + "'");
                }
            }
        }
    }
}

为了测试服务器,我实现了一个生成5个随机位图并将它们发送到服务器的测试客户端

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net.Sockets;

namespace SimplePictureSender
{
    class Program
    {
        static Random Random = new Random();

        static void Main(string[] args)
        {
            Bitmap b;
            TcpClient c = new TcpClient("127.0.0.1", 12345);
            Stream s = c.GetStream();

            using (BinaryWriter w = new BinaryWriter(s))
            {
                for (Int32 i = 0; i < 5; i++)
                {
                    using (MemoryStream m = new MemoryStream())
                    {
                        b = CreateRandomBitmap(640, 480, 1000, 1000); b.Save(m, ImageFormat.Bmp);
                        Console.WriteLine("Picture size is " + m.Length + " Bytes"); Console.WriteLine();

                        m.Seek(0L, SeekOrigin.Begin);

                        w.Write(m.Length);
                        m.WriteTo(w.BaseStream);
                    }
                }
            }

            Console.WriteLine("[ENTER] to exit");
            Console.ReadLine();
        }

        private static Bitmap CreateRandomBitmap(Int32 minX = 100, Int32 minY = 100, Int32 maxDeltaX = 250, Int32 maxDeltaY = 250)
        {
            Console.Write("Generating Picture ... ");

            Bitmap b = new Bitmap(Random.Next(minX, minX + maxDeltaX), Random.Next(minY, minY + maxDeltaY));
            Color c;

            for(Int32 x = 0; x < b.Width; x++)
                for(Int32 y = 0; y < b.Height; y++)
                {
                    c = Color.FromArgb(Random.Next(0, 256), Random.Next(0, 256), Random.Next(0, 256));
                    b.SetPixel(x, y, c);
                }

            Console.WriteLine("Done");

            return b;
        }
    }
}

这一切都很好,很好......太令人惊讶了。

如果我通过以下某个

替换服务器上的行using (BinaryReader r = new BinaryReader(s, Encoding.Unicode))
  • using (BinaryReader r = new BinaryReader(s, Encoding.BigEndianUnicode))
  • using (BinaryReader r = new BinaryReader(s))

设置总是成功传输和存储位图。但是,我希望这些代码中至少有一个失败,因为服务器应该无法正确提取以下数据blob的大小。

为什么有效?是否存在隐式Endianness-Detection?如果现在我要在C中实现一个客户端 - 我是否需要担心字节序?如果不是 - 我的服务器期待什么?

1 个答案:

答案 0 :(得分:0)

请参阅BinaryReader Constructor

编码参数称为“字符编码”,显然对整数写入流的方式没有影响。

如果您的客户端和服务器具有相同的字节序,那么无论字符编码是什么,代码都可以工作,因为您没有在流中写入任何字符,只是字节。