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發送和接收二進制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,界面使用WPFthis

代碼:spa

   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方法可方便轉換成二進制。code

上面只是簡單的實現了傳輸圖片的代碼,實現中應加入錯誤判斷等異常處理。orm

相關文章
相關標籤/搜索