socket(TCP)發送文件

一:因爲在上一個隨筆的基礎之上拓展的因此直接上代碼,客戶端:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.IO;

namespace client
{
    public partial class Client : Form
    {
        public Client()
        {
            InitializeComponent();
     
        }
        //建立 1個客戶端套接字 和1個負責監聽服務端請求的線程  
        Socket socketClient = null;
        Thread threadClient = null;
        private delegate void SetText(string text);
        /// <summary>
        /// 連接服務端
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_login_Click(object sender, EventArgs e)
        {
            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //這裏的ip地址,端口號都是服務端綁定的相關數據。
            IPAddress ip = IPAddress.Parse(tb_ip.Text.Trim());
            IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32(tb_socket.Text.Trim()));
            socketClient.Connect(endpoint);//連接有端口號與IP地址肯定服務端.

            ThreadStart thS = new ThreadStart(this.ReceMsg);

            //客戶端在接受服務端發送過來的數據是經過Socket 中的Receive方法,
            //該方法會阻斷線程,因此咱們本身爲該方法建立了一個線程
            threadClient = new Thread(thS);
            threadClient.IsBackground = true;//設置後臺線程
            threadClient.Start();
            
        }
        //接收服務端數據
        public void ReceMsg()
        {
            while (true)//持續監聽服務端發來的消息
            {
                //定義一個2M的內存緩衝區 用於臨時性存儲接收到的信息
                byte[] buffer = new byte[1024 * 1024 * 2];
                //將客戶端套接字接收到的數據存入內存緩衝區, 並獲取其長度
                int length = socketClient.Receive(buffer);
                //clientSocket.Receive(buffer);//接收服務端發送過來的數據
                string ReceiveMsg = System.Text.Encoding.UTF8.GetString(buffer,0,length);//把接收到的字節數組轉成字符串顯示在文本框中,若是沒有長度,就會以零填充滿,後面的日期就會不顯示了。
                ShowMsg("接收到數據: " + ReceiveMsg);
            }
        }

        //消息框裏面數據
        void ShowMsg(string str)
        {
            if (this.tb_infor.InvokeRequired)
            {
                SetText st = new SetText(ShowMsg);
                this.Invoke(st, new object[] { str });
            }
            else
            {
                //string Ystr = "";
                //if (tb_infor.Text != "")
                //{
                //    Ystr = tb_infor.Text + "\r\n";
                //}
                //tb_infor.Text = Ystr + str + GetCurrentTime();
                //代替上面的方法
                tb_infor.AppendText(str + GetCurrentTime() + "\r\n");
            }
        }
        /// <summary>
        /// 打開文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_openfile_Click(object sender, EventArgs e)
        {

            if (openFileDialog1.ShowDialog() == DialogResult.OK)//這裏須要小括號 ShowDialog()
            {
                tb_openfile.Text = openFileDialog1.FileName;
            }
        }
        #region
        /// <summary>
        /// 發送文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_sendfile_Click(object sender, EventArgs e)
        {
            using (FileStream fs = new FileStream(tb_openfile.Text, FileMode.Open))
            {
                byte[] buffer = new byte[1024 * 1024 * 2];
                int readlength = fs.Read(buffer, 0, buffer.Length);
                byte[] filebuffer = new byte[readlength + 1];
                filebuffer[0] = 1;
                Buffer.BlockCopy(buffer, 0, filebuffer, 1, readlength); //第一參數:表示源數組,第二個:表示從源數組中的哪一個位置開始拷貝,第三個:表示目標數組。,第四個:表示從目標數組的哪一個位置開始填充.,五:表示:拷貝多少數據
                socketClient.Send(filebuffer);
            }
        }
        /// <summary>
        /// 發送消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_sendmessage_Click(object sender, EventArgs e)
        {
            string txtMsg = tb_message.Text;
            sendmessage(txtMsg);

        }
        /// <summary>
        /// 發送信息
        /// </summary>
        /// <param name="txtMsg"></param>
        private void sendmessage(string txtMsg)
        {
            //將輸入的內容字符串轉換爲機器能夠識別的字節數組
            byte[] buffer = Encoding.UTF8.GetBytes(txtMsg);
            byte[] messagebuffer = new byte[buffer.Length + 1];//定義一個新數組,加個標記位,標記是信息
            messagebuffer[0] = 0;//設置標識,表示發送的是字符串
            Buffer.BlockCopy(buffer, 0, messagebuffer, 1, buffer.Length);//源數組中的數據拷貝到新數組中
            socketClient.Send(messagebuffer);
            ShowMsg("發送的數據: " + txtMsg);
 
        }
        #endregion
        /// <summary>
        /// 獲取當前系統時間的方法
        /// </summary>
        /// <returns>當前時間</returns>
        private DateTime GetCurrentTime()
        {
            DateTime currentTime = new DateTime();
            currentTime = DateTime.Now;
            return currentTime;
        }
 
        //快捷鍵 Enter發送信息
        private void tb_message_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {//當光標位於文本框時 若是用戶按下了鍵盤上的Enter鍵 
            if (e.KeyCode == Keys.Enter)
            {
                    //則調用客戶端向服務端發送信息的方法
                    sendmessage(tb_message.Text.Trim());
                
            }

        }
        

       
    }
}

二:服務端

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;

namespace socket
{
    public partial class Server : Form
    {
        public Server()
        {
            InitializeComponent();
            //關閉對文本框的非法線程操做檢查,不建議用
            //TextBox.CheckForIllegalCrossThreadCalls = false;
        }

        Socket socketWatch = null;//負責監聽客戶端的套接字
        Thread threadWatch = null;//負責監聽客戶端的線程
        Thread threadMoveList = null;//負責去掉失敗的socket的ip

        //聲明一個帶參數委託處理文本顯示
        private delegate void SetText(string text);
        //聲明一個處理ip添加到listbox的委託
        private delegate void listboxAdd(string ipsocket);
        //聲明一個處理在listbox去除ip的委託
        private delegate void listboxmove(string ipsocket);
        /// 開始服務端監聽
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_StartServer_Click(object sender, EventArgs e)
        {
            #region
            //建立一個Socket實例
            //第一個參數表示使用ipv4
            //第二個參數表示發送的是數據流
            //第三個參數表示使用的協議是Tcp協議
            socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //獲取ip地址
            IPAddress ip = IPAddress.Parse(tb_ip.Text.Trim());
            //建立一個網絡通訊節點,這個通訊節點包含了ip地址,跟端口號。
            //這裏的端口咱們設置爲1029,這裏設置大於1024,爲何本身查一下端口號範圍使用說明。
            IPEndPoint endPoint = new IPEndPoint(ip, int.Parse(tb_socket.Text.Trim()));
            //設置SOCKET容許多個SOCKET訪問同一個本地IP地址和端口號 
            socketWatch.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            //Socket綁定網路通訊節點
            socketWatch.Bind(endPoint);
            //將套接字的監聽隊列長度限制爲10
            socketWatch.Listen(10);
           
            ShowMsg("開啓監聽!");

            //實力化一個線程上的委託
            ThreadStart threadDelegate = new ThreadStart(this.accpet);//還須要invoke
            //實力化一個處理線程委託的的新線程
            threadWatch = new Thread(threadDelegate);
            //等同於上面兩句newthread = new Thread(new ThreadStart(this.accpet));
            threadWatch.IsBackground = true;
            threadWatch.Start();
            #endregion
        }

        //消息框裏面數據
       public void ShowMsg(string str)
        {
            if (this.tb_infor.InvokeRequired)
            {
                //實例化一個委託
                SetText d = new SetText(ShowMsg);
                this.Invoke(d, new object[] { str });
            }
            else
            {
                
                //string Ystr = "";
                //if (tb_infor.Text != "")
                //{
                //    Ystr = tb_infor.Text + "\r\n";
                //}
                //this.tb_infor.Text = Ystr + str + GetCurrentTime();
                tb_infor.AppendText(str + GetCurrentTime() + "\r\n");
            }
        }
       
       Dictionary<string, Socket> socketDir = new Dictionary<string, Socket>();//將每個與客戶端進行通訊的Socket放到該集合中.
       public void accpet()
        {
            while (true)//注意該循環,服務端要持續監聽,要否則一個客戶端連接事後就沒法連接第二個客戶端了。
            {

               
                    Socket SocketConnection = null;//建立一個負責和客戶端通訊的套接字 
                    //建立一個接收客戶端通訊的Socket
                   
                    SocketConnection = socketWatch.Accept();
                    socketDir.Add(SocketConnection.RemoteEndPoint.ToString(), SocketConnection);//將負責與客戶端進行通訊的Socket實例添加到集合中。
                    //若是監聽到客戶端有連接,則運行到下一部,提示,連接成功!
                    listboxADD(SocketConnection.RemoteEndPoint.ToString());
                    ShowMsg("連接成功!");
                    //建立一個通訊線程 
                    ParameterizedThreadStart pts = new ParameterizedThreadStart(ServerRecMsg);
                    Thread thr = new Thread(pts);

                    //在定義窗體線程的時候,設置線程啓動前狀態就好了,解決異常
                    thr.SetApartmentState(ApartmentState.STA);

                    thr.IsBackground = true;
                    //啓動線程
                    thr.Start(SocketConnection);
               
            }
 
        }
        /// <summary>
        /// 在ip欄裏添加創建socket的ip
        /// </summary>
       private void listboxADD(string ipsocket)
       {
           if (this.ltb_IP.InvokeRequired)
           {
               listboxAdd list = new listboxAdd(listboxADD);
               this.Invoke(list,new object[]{ipsocket});
           }
           else
           {
               ltb_IP.Items.Add(ipsocket);
           }
       }
       
       }
        /// <summary>
        /// 向客戶端發送信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
       private void btn_sendany_Click(object sender, EventArgs e)
       {
           string SendMsg = tb_message.Text;
           if (SendMsg != "")
           {
               byte[] buffer = System.Text.Encoding.UTF8.GetBytes(SendMsg); //將要發送的數據,生成字節數組。
               if (!string.IsNullOrEmpty(this.ltb_IP.Text))
               {
                   string ipendpoint = this.ltb_IP.SelectedItem .ToString();//在服務端,選擇與客戶端進行通訊的IP地址與端口號
                   socketDir[ipendpoint].Send(buffer);//向客戶端發送數據

                   ShowMsg("向客戶端發送了:" + SendMsg);
               }
               else
               {
                   MessageBox.Show("請選擇與哪一個客戶端進行通訊");
               }
               
           }

       }
       /// <summary>
       /// 獲取當前系統時間的方法
       /// </summary>
       /// <returns>當前時間</returns>
       private DateTime GetCurrentTime()
       {
           DateTime currentTime = new DateTime();
           currentTime = DateTime.Now;
           return currentTime;
       }

        /// <summary>
        /// 接收客戶端發來的信息 
        /// </summary>
        /// <param name="socketClientPara">客戶端套接字對象</param>
       private void ServerRecMsg(object socketClientPara)
       {
           Socket socketServer = socketClientPara as Socket;
           while (true)
           {
               int length = -1;
               //建立一個內存緩衝區 其大小爲1024*1024字節  即1M
               byte[] arrServerRecMsg = new byte[1024 * 1024 * 2];
               try  //因爲Socket中的Receive方法容易拋出異常,因此咱們在這裏要捕獲異常。
               {
                   //將接收到的信息存入到內存緩衝區,並返回其字節數組的長度
                   length = socketServer.Receive(arrServerRecMsg);
               }
               catch (SocketException ex)//注意:在捕獲異常時,先肯定具體的異常類型。
               {
                   ShowMsg("出現了異常:" + ex.Message);
                   socketDir.Remove(socketServer.RemoteEndPoint.ToString());//若是出現了異常,將該Socket實例從集合中移除


                   //ParameterizedThreadStart Delegatemove = new ParameterizedThreadStart(listboxmoveway);//用ParameterizedThreadStart其方法能夠帶一個object類型的參數
                   //threadMoveList = new Thread(Delegatemove);
                   //threadMoveList.IsBackground = true;
                   //threadMoveList.Start();
                   //listboxmoveway(socketServer.RemoteEndPoint);//調用方法
                   //socketServer.Close();
                   break;//出現異常之後,終止整個循環的執行
               }
               catch (Exception ex)
               {
                   ShowMsg("出現了異常:" + ex.Message);
                   break;
               }
               if (arrServerRecMsg[0] == 0)//表示字符串
                {
                    
                    //將機器接受到的字節數組轉換爲人能夠讀懂的字符串
                   string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 1, length-1);
                   //將發送的字符串信息附加到文本框txtMsg上  
                   ShowMsg("接受客戶端數據:" + strSRecMsg);
                }
               else if (arrServerRecMsg[0] == 1)
               {
                   SaveFileDialog savefile=new SaveFileDialog();
                   if(savefile.ShowDialog()==DialogResult.OK)
                   {
                       using(FileStream fs=new FileStream(savefile.FileName,FileMode.Create))
                       {
                           fs.Write(arrServerRecMsg, 1, length - 1);//將文件寫到磁盤上,從1開始到receiveLength-1
                              ShowMsg("文件寫成功!" ); 
                       }
                   }
                   
               }
              
 
           }
 
       }
        
        

    }
}
相關文章
相關標籤/搜索