zoukankan      html  css  js  c++  java
  • Socket 传一幅图片给另一个终端

    练习Socket传文件,先添加一个组件,简化socket发送和接收文件,

    获取IP和端口的类

        public static class AddressHelper
        {
            /// <summary>
            /// 获取本机IPv4地址的集合
            /// </summary>
            /// <returns></returns>
            public static IPAddress[] GetLocalhostIPv4Addresses()
            {
                String LocalhostName = Dns.GetHostName();
    
                IPHostEntry host = Dns.GetHostEntry(LocalhostName);
                List<IPAddress> addresses=new List<IPAddress>();
                foreach (IPAddress ip in host.AddressList)
                {
                    if (ip.AddressFamily == AddressFamily.InterNetwork) 
                        addresses.Add(ip);
                }
                return addresses.ToArray();
            }
    
    
            /// <summary>
            /// 以交互方式生成有效的远程主机访问终结点,适用于控制台程序
            /// </summary>
            /// <returns></returns>
            public static IPEndPoint GetRemoteMachineIPEndPoint()
            {
                IPEndPoint iep = null;
                try
                {
                    Console.Write("请输入远程主机的IP地址:");
                    IPAddress address = IPAddress.Parse(Console.ReadLine());
                    Console.Write("请输入远程主机打开的端口号:");
                    int port = Convert.ToInt32(Console.ReadLine());
                    if (port > 65535 || port < 1024)
                        throw new Exception("端口号应该为[1024,65535]范围内的整数");
                    iep = new IPEndPoint(address, port);
    
                }
                catch (ArgumentNullException)
                {
                    Console.WriteLine("输入的数据有误!");
                }
                catch (FormatException)
                {
                    Console.WriteLine("输入的数据有误!");
                }
    
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                return iep;
            }
    
            /// <summary>
            /// 获取本机当前可用的端口号,此方法是线程安全的
            /// </summary>
            /// <returns></returns>
            public static int GetOneAvailablePortInLocalhost()
            {
                Mutex mtx = new Mutex(false, "MyNetworkLibrary.AddressHelper.GetOneAvailablePort");
                try
                {
                    mtx.WaitOne();
                    IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
                    using (Socket tempSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                    {
                        tempSocket.Bind(ep);
                        IPEndPoint ipep = tempSocket.LocalEndPoint as IPEndPoint;
                        return ipep.Port;
                    }
                }
                finally
                {
                    mtx.ReleaseMutex();
                }
            }
        }

    socket发送和接收二进制

     public static class SocketHelper
        {
            /// <summary>
            /// 接收变长的数据,要求其打头的4个字节代表有效数据的长度
            /// </summary>
            /// <param name="s"></param>
            /// <returns></returns>
            public static byte[] ReceiveVarData(Socket s)
            {
                if (s == null)
                    throw new ArgumentNullException("s");
                int total = 0;  //已接收的字节数
                int recv;
                //接收4个字节,得到“消息长度”
                byte[] datasize = new byte[4];
                recv = s.Receive(datasize, 0, 4, 0);
                int size = BitConverter.ToInt32(datasize, 0);
                //按消息长度接收数据
                int dataleft = size;
                byte[] data = new byte[size];
                while (total < size)
                {
                    recv = s.Receive(data, total, dataleft, 0);
                    if (recv == 0)
                    {
                        break;
                    }
                    total += recv;
                    dataleft -= recv;
                }
                return data;
            }
    
            /// <summary>
            /// 发送变长的数据,将数据长度附加于数据开头
            /// </summary>
            /// <param name="s"></param>
            /// <param name="data"></param>
            /// <returns></returns>
            public static int SendVarData(Socket s, byte[] data)
            {
                int total = 0;
                int size = data.Length;  //要发送的消息长度
                int dataleft = size;     //剩余的消息
                int sent;
                //将消息长度(int类型)的,转为字节数组
                byte[] datasize = BitConverter.GetBytes(size);
                //将消息长度发送出去
                sent = s.Send(datasize);
                //发送消息剩余的部分
                while (total < size)
                {
                    sent = s.Send(data, total, dataleft, SocketFlags.None);
                    total += sent;
                    dataleft -= sent;
                }
                return total;
            }
        }

     好,现在开始制作socket,界面使用WPF

    代码:

       public partial class MainWindow : Window
        {
            Socket server = null;
            string picPath = "";
            public MainWindow()
            {
                InitializeComponent();
                Init();
            }
    
            private void Init()
            {
                //初始化
                var ip = AddressHelper.GetLocalhostIPv4Addresses().First();
                var port = AddressHelper.GetOneAvailablePortInLocalhost();
                txtIp.Text = ip.ToString();
                txtPort.Text = port.ToString();
    
                IPEndPoint iep = new IPEndPoint(ip, port);
                server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                server.Bind(iep);
                server.Listen(1);
                //启动线程开始接收数据
                DoWork();
                tbinfo.Text = iep.ToString() + "已启动监听";
            }
    
            private Task DoWork()
            {
                return Task.Run(() =>
                  {
                      //创建委托,更新图片控件
                      Action<byte[]> action = buf =>
                      {
                          img.Source = ByteToBitmapImage(buf);
                      };
                      while (true)
                      {
                          var client = server.Accept();
                          var data = SocketHelper.ReceiveVarData(client);
    
                          this.Dispatcher.BeginInvoke(action, data);
                          client.Shutdown(SocketShutdown.Both);
                          client.Close();
                      }
                  });
    
            }
            //二进制转图片
            public BitmapImage ByteToBitmapImage(byte[] buf)
            {
                BitmapImage bmp = new BitmapImage();
                MemoryStream ms = new MemoryStream(buf);
                ms.Position = 0;
                bmp.BeginInit();
                bmp.StreamSource = ms;
                bmp.EndInit();
                return bmp;
            }
            //选择图片
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    picPath = ofd.FileName;
                    img.Source = new BitmapImage(new Uri(picPath));
                }
            }
            //取远程终端的IPEndPoint
            private IPEndPoint getRemIEP()
            {
                return new IPEndPoint(IPAddress.Parse(txtIp.Text), int.Parse(txtPort.Text));
            }
            //发送
            private void Button_Click_1(object sender, RoutedEventArgs e)
            {
                var newSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                using (newSocket)
                {
                    IPEndPoint remIep = getRemIEP();
                    newSocket.Connect(remIep);
                    var buf = File.ReadAllBytes(picPath);
                    SocketHelper.SendVarData(newSocket, buf);
                }
            }
        }

    上面代码要添加两个引用,一个是System.Windows.Forms,另一个就是最上面所建的类,这时可以打开两个应用,在端口处输入远程的端口,相互就可以发送图片,并能显示图片,如下图

    相互传输使用二进制传输,文件转二进制,使用File.ReadAllBytes方法可方便转换成二进制。

    上面只是简单的实现了传输图片的代码,实现中应加入错误判断等异常处理。

  • 相关阅读:
    React 之 jsx
    React 之 初识
    vue 之 svg
    c#进阶 之 特性
    c#进阶 之 反射Reflection
    面试题解答分析
    c#进阶 之 泛型
    c#进阶 之 修饰符
    c#进阶 之 方法汇总
    微信开发学习(二)
  • 原文地址:https://www.cnblogs.com/lunawzh/p/6694138.html
Copyright © 2011-2022 走看看