狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

C# Socket服務(wù)端與客戶端通信(包含大文件的斷點(diǎn)傳輸、端口復(fù)用技術(shù))

admin
2021年3月3日 12:26 本文熱度 3880
步驟:

一、服務(wù)端的建立

1.服務(wù)端的項(xiàng)目建立以及頁(yè)面布局

2.各功能按鍵的事件代碼

  1)傳輸類(lèi)型說(shuō)明以及全局變量

  2)Socket通信服務(wù)端具體步驟:

    (1)建立一個(gè)Socket

    (2)接收信息

    (3)發(fā)送數(shù)據(jù)(這里分發(fā)送字符串、文件(包含大文件)、震動(dòng))

二、客戶端的建立

1.服務(wù)端的項(xiàng)目建立以及頁(yè)面布局

2.各功能按鍵的事件代碼

  1)傳輸類(lèi)型說(shuō)明以及全局變量

  2)Socket通信服務(wù)端具體步驟:

    (1)建立一個(gè)Socket

    (2)接收信息

    (3)發(fā)送數(shù)據(jù)(這里分發(fā)送字符串、文件(包含大文件)、震動(dòng))


注意:此圖是Socket通信的精華,在使用Socket通信時(shí),有什么迷惑的可以看看此圖,下面我們講解的時(shí)候也是參照此圖

 

Socket大家肯定很熟悉,對(duì)已內(nèi)部的通信邏輯,肯定也有一定得了解---

對(duì)于Socket研究了兩天寫(xiě)了一個(gè)小程序,通過(guò)Socket服務(wù)端與客戶端的通信,以及大文件之間斷點(diǎn)的傳輸(這里只做了服務(wù)端給客戶端傳送大文件,如果想把客戶端的大文件傳送給服務(wù)端也是一樣的道理,看了文章,大家肯定可以自己實(shí)現(xiàn))······

(自己才疏學(xué)淺,如有bug請(qǐng)諒解,但功能還是能實(shí)現(xiàn)的)

下面根據(jù)步驟進(jìn)入正題:

一、服務(wù)端的建立

1.服務(wù)端的項(xiàng)目建立以及頁(yè)面布局


新建解決方案“Socket通信”以及兩個(gè)Winform項(xiàng)目(1)SockeClient——客戶端    (2)SocketServer——服務(wù)器


給服務(wù)端界面布局——參照上圖(這個(gè)大家肯定都是手到擒來(lái)就不累贅了······)

2.各功能按鍵的事件代碼

先把整個(gè)服務(wù)端的代碼貼出來(lái),然后我們?cè)谝灰恢v解

namespace SocketServer

{

    public partial class Form1 : Form

    {

        //說(shuō)明:在傳遞信息的時(shí)候,會(huì)在需要傳遞的信息前面加一個(gè)字符來(lái)標(biāo)識(shí)傳遞的是不同的信息

        // 0:表示傳遞的是字符串信息

        // 1:表示傳遞的是文件信息

        // 2:表示的是震動(dòng)

 

        /// <summary>

        /// 用來(lái)存放連接服務(wù)的客戶端的IP地址和端口號(hào),對(duì)應(yīng)的Socket

        /// </summary>

        Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();

 

        public Form1()

        {

            InitializeComponent();

        }

 

        private void Form1_Load(object sender, EventArgs e)

        {

            //不檢測(cè)跨線程之間的空間調(diào)用

            Control.CheckForIllegalCrossThreadCalls = false;

        }

 

        /// <summary>

        /// 開(kāi)啟監(jiān)聽(tīng)

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnStart_Click(object sender, EventArgs e)

        {

            try

            {

                //當(dāng)點(diǎn)擊開(kāi)始監(jiān)聽(tīng)的時(shí)候 在服務(wù)器端創(chuàng)建一個(gè)負(fù)責(zé)監(jiān)IP地址跟端口號(hào)的Socket

                Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                //獲取IP

                IPAddress ip = IPAddress.Any;

                //創(chuàng)建端口號(hào)

                IPEndPoint port = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));

                //監(jiān)聽(tīng)

                socketWatch.Bind(port);

                ShowMsg("監(jiān)聽(tīng)成功");

                socketWatch.Listen(10);

                //新建線程,去接收客戶端發(fā)來(lái)的信息

                Thread td = new Thread(AcceptMgs);

                td.IsBackground = true;

                td.Start(socketWatch);

            }

            catch

            {

            }          

        }

 

        /// <summary>

        /// 接收客戶端發(fā)送的信息

        /// </summary>

        /// <param name="o"></param>

        private void AcceptMgs(object o)

        {

            try

            {

                Socket socketWatc = (Socket)o;

                while (true)

                {

                    ////負(fù)責(zé)跟客戶端通信的Socket

                    Socket socketSend = socketWatc.Accept();

                    //將遠(yuǎn)程連接的客戶端的IP地址和Socket存入集合中

                    dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend);

                    //將遠(yuǎn)程連接的客戶端的IP地址和端口號(hào)存儲(chǔ)下拉框中

                    cboUsers.Items.Add(socketSend.RemoteEndPoint.ToString());

                    ShowMsg(socketSend.RemoteEndPoint.ToString() + ": 連接成功");

                    //新建線程循環(huán)接收客戶端發(fā)來(lái)的信息

                    Thread td = new Thread(Recive);

                    td.IsBackground = true;

                    td.Start(socketSend);

                }

            }

            catch { }

        }

 

        /// <summary>

        /// 接收客戶端發(fā)來(lái)的數(shù)據(jù),并顯示出來(lái)

        /// </summary>

        private void Recive(object o)

        {

            Socket socketSend = (Socket)o;

            try

            {

                while (true)

                {

                    //客戶端連接成功后,服務(wù)器應(yīng)該接受客戶端發(fā)來(lái)的消息

                     

                    if (socketSend == null)

                    {

                        MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

                        continue;

                    }

                    byte[] buffer = new byte[1024 * 1024 * 2];

                    //實(shí)際接受到的有效字節(jié)數(shù)

                    int r = socketSend.Receive(buffer);

                    //如果客戶端關(guān)閉,發(fā)送的數(shù)據(jù)就為空,然后就跳出循環(huán)

                    if (r == 0)

                    {

                        break;

                    }                  

                    if (buffer[0] == 0) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是0,說(shuō)明接收的字符串信息

                    {

                        string strMsg = Encoding.UTF8.GetString(buffer, 1, r - 1);

                        ShowMsg(socketSend.RemoteEndPoint.ToString() + ": " + strMsg);

                    }

                    else if (buffer[0] == 1) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是1,說(shuō)明接收的是文件

                    {

                        string filePath = "";

                        SaveFileDialog sfd = new SaveFileDialog();

                        sfd.Title = "保存文件";

                        sfd.InitialDirectory = @"C:\Users\Administrator\Desktop";

                        sfd.Filter = "文本文件|*.txt|圖片文件|*.jpg|視頻文件|*.avi|所有文件|*.*";

                        //如果沒(méi)有選擇保存文件路徑就一直打開(kāi)保存框

                        while (true)

                        {

                            sfd.ShowDialog(this);

                            filePath = sfd.FileName;

                            if (string.IsNullOrEmpty(filePath))

                            {

                                continue;

                            }

                            else

                            {

                                break;

                            }

                        }

                        //保存接收的文件

                        using (FileStream fsWrite = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write))

                        {

                            fsWrite.Write(buffer, 1, r - 1);

                        }

                        ShowMsg(socketSend.RemoteEndPoint + ": 接收文件成功");

                         

                    }

                    else if (buffer[0] == 2) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是2,說(shuō)明接收的是震動(dòng)

                    {

                        ZD();

                    }

                }

            }

            catch{}         

        }

        /// <summary>

        /// 顯示信息

        /// </summary>

        /// <param name="message"></param>

        private void ShowMsg(string message)

        {

            txtLog.AppendText(message + "\r\n");

        }

 

        /// <summary>

        /// 發(fā)送信息

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnSend_Click(object sender, EventArgs e)

        {

             

            //獲得選中客戶端ip對(duì)應(yīng)的通信Socket      

            if (cboUsers.SelectedItem == null)

            {

                MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

                return;

            }

            Socket socketSend = dicSocket[cboUsers.SelectedItem.ToString()];

            if (socketSend == null)

            {

                MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

                return;

            }

            string strSend=txtMsg.Text;

            try

            {

                byte[] buffer = Encoding.UTF8.GetBytes(strSend);

                //獲得發(fā)送的信息時(shí)候,在數(shù)組前面加上一個(gè)字節(jié) 0

                List<byte> list = new List<byte>();

                list.Add(0);

                list.AddRange(buffer);

                //將泛型集合轉(zhuǎn)換為數(shù)組

                byte[] newBuffer = list.ToArray();

                //將了標(biāo)識(shí)字符的字節(jié)數(shù)組傳遞給客戶端

                socketSend.Send(newBuffer);

                txtMsg.Text = "";

            }

            catch

            {

            }           

        }

 

        /// <summary>

        /// 選擇文件

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnSelect_Click(object sender, EventArgs e)

        {

            //打開(kāi)文件

            OpenFileDialog ofd = new OpenFileDialog();

            ofd.Title = "選擇要傳的文件";

            ofd.InitialDirectory = @"C:\Users\Administrator\Desktop";

            ofd.Filter = "文本文件|*.txt|圖片文件|*.jpg|視頻文件|*.avi|所有文件|*.*";

            ofd.ShowDialog();

            //得到選擇文件的路徑

            txtPath.Text = ofd.FileName;

        }

 

        /// <summary>

        /// 發(fā)送文件

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnSendFile_Click(object sender, EventArgs e)

        {

            //判斷是否選擇了要發(fā)送的客戶端

            if (cboUsers.SelectedItem == null)

            {

                MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

                return;

            }

            Socket socketSend = dicSocket[cboUsers.SelectedItem.ToString()];

            if (socketSend == null)

            {

                MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

                return;

            }

            string filePath = txtPath.Text;

            if (string.IsNullOrEmpty(filePath))

            {

                MessageBox.Show("請(qǐng)選擇文件");

                return;

            }

            Thread td = new Thread(SendBigFile);

            td.IsBackground = true;

            td.Start();

        }

 

        /// <summary>

        /// 大文件斷點(diǎn)傳送

        /// </summary>

        private void SendBigFile()

        {

            string filePath = txtPath.Text;

            Socket socketSend = dicSocket[cboUsers.SelectedItem.ToString()];

            try

            {

                //讀取選擇的文件

                using (FileStream fsRead = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read))

                {

                    //1. 第一步:發(fā)送一個(gè)包,表示文件的長(zhǎng)度,讓客戶端知道后續(xù)要接收幾個(gè)包來(lái)重新組織成一個(gè)文件

                    long length = fsRead.Length;

                    byte[] byteLength = Encoding.UTF8.GetBytes(length.ToString());

                    //獲得發(fā)送的信息時(shí)候,在數(shù)組前面加上一個(gè)字節(jié) 1

                    List<byte> list = new List<byte>();

                    list.Add(1);

                    list.AddRange(byteLength);

                    socketSend.Send(list.ToArray()); //

                    //2. 第二步:每次發(fā)送一個(gè)1MB的包,如果文件較大,則會(huì)拆分為多個(gè)包

                    byte[] buffer = new byte[1024 * 1024];

                    long send = 0; //發(fā)送的字節(jié)數(shù)                  

                    while (true)  //大文件斷點(diǎn)多次傳輸

                    {

                        int r = fsRead.Read(buffer, 0, buffer.Length);

                        if (r == 0)

                        {

                            break;

                        }

                        socketSend.Send(buffer, 0, r, SocketFlags.None);

                        send += r;

                        ShowMsg(string.Format("{0}: 已發(fā)送:{1}/{2}", socketSend.RemoteEndPoint, send, length));

                    }

                    ShowMsg("發(fā)送完成");

                    txtPath.Text = "";

                }

            }

            catch

            {

            }

        }

 

        /// <summary>

        /// 震動(dòng)

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnZD_Click(object sender, EventArgs e)

        {

            //判斷是否選擇了要發(fā)送的客戶端

            if (cboUsers.SelectedItem == null)

            {

                MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

                return;

            }

            Socket socketSend = dicSocket[cboUsers.SelectedItem.ToString()];

            if (socketSend == null)

            {

                MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

                return;

            }

            try

            {

                // 首字節(jié)是2說(shuō)明是震動(dòng)

                byte[] buffer = new byte[1];

                buffer[0] = 2;

                socketSend.Send(buffer);

            }

            catch

            {

            }

        }

 

        /// <summary>

        /// 震動(dòng)

        /// </summary>

        private void ZD()

        {

            //獲取當(dāng)前窗體的坐標(biāo)

            Point point = this.Location;

            //反復(fù)給窗體坐標(biāo)復(fù)制一百次,達(dá)到震動(dòng)的效果

            for (int i = 0; i < 100; i++)

            {

                this.Location = new Point(point.X - 5, point.Y - 5);

                this.Location = new Point(point.X + 5, point.Y + 5);

            }

            this.Location = point;

        }

    }

}

1)傳輸類(lèi)型說(shuō)明以及全局變量


這些說(shuō)明以及全局變量,說(shuō)的也比較清楚,也不累贅了。

2)Socket通信服務(wù)端具體步驟:

(這些步驟都是根據(jù)第一個(gè)圖來(lái)的)

 (1)建立一個(gè)Socket

/// <summary>
/// 開(kāi)啟監(jiān)聽(tīng)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStart_Click(object sender, EventArgs e)
{
    try
    {
        //當(dāng)點(diǎn)擊開(kāi)始監(jiān)聽(tīng)的時(shí)候 在服務(wù)器端創(chuàng)建一個(gè)負(fù)責(zé)監(jiān)IP地址跟端口號(hào)的Socket
        Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //獲取IP
        IPAddress ip = IPAddress.Any;
        //創(chuàng)建端口號(hào)
        IPEndPoint port = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
        //監(jiān)聽(tīng)
        socketWatch.Bind(port);
        ShowMsg("監(jiān)聽(tīng)成功");
        socketWatch.Listen(10);
        //新建線程,去接收客戶端發(fā)來(lái)的信息
        Thread td = new Thread(AcceptMgs);
        td.IsBackground = true;
        td.Start(socketWatch);
    }
    catch
    {
    }
}

在開(kāi)啟監(jiān)聽(tīng)按鈕里,我們建立了Socket,以及監(jiān)聽(tīng)的最大客戶端數(shù) socketWatch.Listen(10)

由于服務(wù)端會(huì)不停的去監(jiān)視接收客戶端發(fā)來(lái)的信息,如果把這個(gè)工作放到主線程里,程序會(huì)出現(xiàn)假死的現(xiàn)象,所以這里給他放到一個(gè)新的線程里。

(2)接收信息

/// <summary>

/// 接收客戶端發(fā)送的信息

/// </summary>

/// <param name="o"></param>

private void AcceptMgs(object o)

{

    try

    {

        Socket socketWatc = (Socket)o;

        while (true)

        {

            ////負(fù)責(zé)跟客戶端通信的Socket

            Socket socketSend = socketWatc.Accept();

            //將遠(yuǎn)程連接的客戶端的IP地址和Socket存入集合中

            dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend);

            //將遠(yuǎn)程連接的客戶端的IP地址和端口號(hào)存儲(chǔ)下拉框中

            cboUsers.Items.Add(socketSend.RemoteEndPoint.ToString());

            ShowMsg(socketSend.RemoteEndPoint.ToString() + ": 連接成功");

            //新建線程循環(huán)接收客戶端發(fā)來(lái)的信息

            Thread td = new Thread(Recive);

            td.IsBackground = true;

            td.Start(socketSend);

        }

    }

    catch { }

}


接收信息是會(huì)根據(jù)接收到字節(jié)數(shù)字的第一個(gè)字節(jié)來(lái)判斷接收到的是什么,這個(gè)在方法Recive里進(jìn)行判斷:

/// <summary>

/// 接收客戶端發(fā)來(lái)的數(shù)據(jù),并顯示出來(lái)

/// </summary>

private void Recive(object o)

{

    Socket socketSend = (Socket)o;

    try

    {

        while (true)

        {

            //客戶端連接成功后,服務(wù)器應(yīng)該接受客戶端發(fā)來(lái)的消息

             

            if (socketSend == null)

            {

                MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

                continue;

            }

            byte[] buffer = new byte[1024 * 1024 * 2];

            //實(shí)際接受到的有效字節(jié)數(shù)

            int r = socketSend.Receive(buffer);

            //如果客戶端關(guān)閉,發(fā)送的數(shù)據(jù)就為空,然后就跳出循環(huán)

            if (r == 0)

            {

                break;

            }                  

            if (buffer[0] == 0) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是0,說(shuō)明接收的字符串信息

            {

                string strMsg = Encoding.UTF8.GetString(buffer, 1, r - 1);

                ShowMsg(socketSend.RemoteEndPoint.ToString() + ": " + strMsg);

            }

            else if (buffer[0] == 1) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是1,說(shuō)明接收的是文件

            {

                string filePath = "";

                SaveFileDialog sfd = new SaveFileDialog();

                sfd.Title = "保存文件";

                sfd.InitialDirectory = @"C:\Users\Administrator\Desktop";

                sfd.Filter = "文本文件|*.txt|圖片文件|*.jpg|視頻文件|*.avi|所有文件|*.*";

                //如果沒(méi)有選擇保存文件路徑就一直打開(kāi)保存框

                while (true)

                {

                    sfd.ShowDialog(this);

                    filePath = sfd.FileName;

                    if (string.IsNullOrEmpty(filePath))

                    {

                        continue;

                    }

                    else

                    {

                        break;

                    }

                }

                //保存接收的文件

                using (FileStream fsWrite = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write))

                {

                    fsWrite.Write(buffer, 1, r - 1);

                }

                ShowMsg(socketSend.RemoteEndPoint + ": 接收文件成功");

                 

            }

            else if (buffer[0] == 2) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是2,說(shuō)明接收的是震動(dòng)

            {

                ZD();

            }

        }

    }

    catch{}         

}


(3)發(fā)送數(shù)據(jù)(這里分發(fā)送字符串、文件(包含大文件)、震動(dòng))

發(fā)送字符串信息

/// <summary>

/// 發(fā)送信息

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btnSend_Click(object sender, EventArgs e)

{

     

    //獲得選中客戶端ip對(duì)應(yīng)的通信Socket      

    if (cboUsers.SelectedItem == null)

    {

        MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

        return;

    }

    Socket socketSend = dicSocket[cboUsers.SelectedItem.ToString()];

    if (socketSend == null)

    {

        MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

        return;

    }

    string strSend=txtMsg.Text;

    try

    {

        byte[] buffer = Encoding.UTF8.GetBytes(strSend);

        //獲得發(fā)送的信息時(shí)候,在數(shù)組前面加上一個(gè)字節(jié) 0

        List<byte> list = new List<byte>();

        list.Add(0);

        list.AddRange(buffer);

        //將泛型集合轉(zhuǎn)換為數(shù)組

        byte[] newBuffer = list.ToArray();

        //將了標(biāo)識(shí)字符的字節(jié)數(shù)組傳遞給客戶端

        socketSend.Send(newBuffer);

        txtMsg.Text = "";

    }

    catch

    {

    }           

}


發(fā)送震動(dòng)

/// <summary>

/// 震動(dòng)

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btnZD_Click(object sender, EventArgs e)

{

    //判斷是否選擇了要發(fā)送的客戶端

    if (cboUsers.SelectedItem == null)

    {

        MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

        return;

    }

    Socket socketSend = dicSocket[cboUsers.SelectedItem.ToString()];

    if (socketSend == null)

    {

        MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

        return;

    }

    try

    {

        // 首字節(jié)是2說(shuō)明是震動(dòng)

        byte[] buffer = new byte[1];

        buffer[0] = 2;

        socketSend.Send(buffer);

    }

    catch

    {

         

    }

     

}

/// <summary>

/// 震動(dòng)

/// </summary>

private void ZD()

{

    //獲取當(dāng)前窗體的坐標(biāo)

    Point point = this.Location;

    //反復(fù)給窗體坐標(biāo)復(fù)制一百次,達(dá)到震動(dòng)的效果

    for (int i = 0; i < 100; i++)

    {

        this.Location = new Point(point.X - 5, point.Y - 5);

        this.Location = new Point(point.X + 5, point.Y + 5);

    }

    this.Location = point;

}


發(fā)送文件(包含大文件)

首先要選擇文件

/// <summary>

/// 選擇文件

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btnSelect_Click(object sender, EventArgs e)

{

    //打開(kāi)文件

    OpenFileDialog ofd = new OpenFileDialog();

    ofd.Title = "選擇要傳的文件";

    ofd.InitialDirectory = @"C:\Users\Administrator\Desktop";

    ofd.Filter = "文本文件|*.txt|圖片文件|*.jpg|視頻文件|*.avi|所有文件|*.*";

    ofd.ShowDialog();

    //得到選擇文件的路徑

    txtPath.Text = ofd.FileName;

}


然后在發(fā)送文件

/// <summary>

/// 發(fā)送文件

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btnSendFile_Click(object sender, EventArgs e)

{

    //判斷是否選擇了要發(fā)送的客戶端

    if (cboUsers.SelectedItem == null)

    {

        MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

        return;

    }

    Socket socketSend = dicSocket[cboUsers.SelectedItem.ToString()];

    if (socketSend == null)

    {

        MessageBox.Show("請(qǐng)選擇要發(fā)送的客戶端");

        return;

    }

    string filePath = txtPath.Text;

    if (string.IsNullOrEmpty(filePath))

    {

        MessageBox.Show("請(qǐng)選擇文件");

        return;

    }

    Thread td = new Thread(SendBigFile);

    td.IsBackground = true;

    td.Start();

     

}

/// <summary>

/// 大文件斷點(diǎn)傳送

/// </summary>

private void SendBigFile()

{

    string filePath = txtPath.Text;

    Socket socketSend = dicSocket[cboUsers.SelectedItem.ToString()];

    try

    {

        //讀取選擇的文件

        using (FileStream fsRead = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read))

        {

            //1. 第一步:發(fā)送一個(gè)包,表示文件的長(zhǎng)度,讓客戶端知道后續(xù)要接收幾個(gè)包來(lái)重新組織成一個(gè)文件

            long length = fsRead.Length;

            byte[] byteLength = Encoding.UTF8.GetBytes(length.ToString());

            //獲得發(fā)送的信息時(shí)候,在數(shù)組前面加上一個(gè)字節(jié) 1

            List<byte> list = new List<byte>();

            list.Add(1);

            list.AddRange(byteLength);

            socketSend.Send(list.ToArray()); //

            //2. 第二步:每次發(fā)送一個(gè)4KB的包,如果文件較大,則會(huì)拆分為多個(gè)包

            byte[] buffer = new byte[1024 * 1024];

            long send = 0; //發(fā)送的字節(jié)數(shù)                  

            while (true)  //大文件斷點(diǎn)多次傳輸

            {

                int r = fsRead.Read(buffer, 0, buffer.Length);

                if (r == 0)

                {

                    break;

                }

                socketSend.Send(buffer, 0, r, SocketFlags.None);

                send += r;

                ShowMsg(string.Format("{0}: 已發(fā)送:{1}/{2}", socketSend.RemoteEndPoint, send, length));

            }

            ShowMsg("發(fā)送完成");

            txtPath.Text = "";

        }

    }

    catch

    {

    }

}


注意:(1)發(fā)送文件的時(shí)候會(huì)分兩步發(fā)送 :第一步:發(fā)送一個(gè)包,表示文件的長(zhǎng)度,讓客戶端知道后續(xù)要接收幾個(gè)包來(lái)重新組織成一個(gè)文件

                                                 第二步:每次發(fā)送一個(gè)1MB的包,如果文件較大,則會(huì)拆分為多個(gè)包

     (2)每個(gè)客戶端連接服務(wù)端的啥時(shí)候,都會(huì)把客戶端的ip以及端口號(hào),放到下拉框里,想給那個(gè)客戶端發(fā)信息,就選擇對(duì)應(yīng)的客戶端


二、客戶端的建立

1.客戶端的項(xiàng)目建立以及頁(yè)面布局


客戶端的界面布局與服務(wù)端很像,就是把對(duì)應(yīng)的開(kāi)始監(jiān)聽(tīng)換成連接,當(dāng)然代碼也會(huì)有所改變,后面會(huì)講到·····

2.各功能按鍵的事件代碼

先把整個(gè)服客戶端的代碼貼出來(lái),然后我們?cè)谝灰恢v解

namespace SocketClient

{

    public partial class Form1 : Form

    {


        //說(shuō)明:在傳遞信息的時(shí)候,會(huì)在需要傳遞的信息前面加一個(gè)字符來(lái)標(biāo)識(shí)傳遞的是不同的信息

        // 0:表示傳遞的是字符串信息

        // 1:表示傳遞的是文件信息

        // 2:表示的是震動(dòng)


        /// <summary>

        /// 用來(lái)存放連接服務(wù)的IP地址和端口號(hào),對(duì)應(yīng)的Socket (這個(gè)為了以后的擴(kuò)展用,現(xiàn)在暫時(shí)沒(méi)用)

        /// </summary>

        Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();


        /// <summary>

        /// 存儲(chǔ)保存文件的路徑

        /// </summary>

        string  filePath = "";

        /// <summary>

        /// 負(fù)責(zé)通信的Socket

        /// </summary>

        Socket socketSend;       


        public Form1()

        {

            InitializeComponent();

        }


        private void Form1_Load(object sender, EventArgs e)

        {

            //不檢測(cè)跨線程之間的空間調(diào)用

            Control.CheckForIllegalCrossThreadCalls = false;

        }


        /// <summary>

        /// 建立連接

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnStart_Click(object sender, EventArgs e)

        {

            try

            {

                //創(chuàng)建負(fù)責(zé)通信的Socket

                socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                //獲取服務(wù)端的IP

                IPAddress ip = IPAddress.Parse(txtServer.Text.Trim());

                //獲取服務(wù)端的端口號(hào)

                IPEndPoint port = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));

                //獲得要連接的遠(yuǎn)程服務(wù)器應(yīng)用程序的IP地址和端口號(hào)

                socketSend.Connect(port);

                ShowMsg("連接成功");

                //新建線程,去接收客戶端發(fā)來(lái)的信息

                Thread td = new Thread(AcceptMgs);

                td.IsBackground = true;

                td.Start();

            }

            catch { }

        }


        /// <summary>

        /// 接收數(shù)據(jù)

        /// </summary>

        private void AcceptMgs()

        {           

            try

            {

                /// <summary>

                /// 存儲(chǔ)大文件的大小

                /// </summary>

                long length = 0;

                long recive = 0; //接收的大文件總的字節(jié)數(shù)

                while (true)

                {

                    byte[] buffer = new byte[1024 * 1024];

                    int r = socketSend.Receive(buffer);

                    if (r == 0)

                    {

                        break;

                    }

                    if (length > 0)  //判斷大文件是否已經(jīng)保存完

                    {

                        //保存接收的文件

                        using (FileStream fsWrite = new FileStream(filePath, FileMode.Append, FileAccess.Write))

                        {

                            fsWrite.Write(buffer, 0, r);

                            length -= r; //減去每次保存的字節(jié)數(shù)

                            ShowMsg(string.Format("{0}: 已接收:{1}/{2}", socketSend.RemoteEndPoint, recive-length, recive));

                            if (length <= 0)

                            {

                                ShowMsg(socketSend.RemoteEndPoint + ": 接收文件成功");

                            }

                            continue;

                        }                        

                    }

                    if (buffer[0] == 0) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是0,說(shuō)明接收的字符串信息

                    {

                        string strMsg = Encoding.UTF8.GetString(buffer, 1, r - 1);

                        ShowMsg(socketSend.RemoteEndPoint.ToString() + ": " + strMsg);

                    }

                    else if (buffer[0] == 1) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是1,說(shuō)明接收的是文件

                    {

                        length = int.Parse(Encoding.UTF8.GetString(buffer,1,r-1));

                        recive = length;

                        filePath = "";

                        SaveFileDialog sfd = new SaveFileDialog();

                        sfd.Title = "保存文件";

                        sfd.InitialDirectory = @"C:\Users\Administrator\Desktop";

                        sfd.Filter = "文本文件|*.txt|圖片文件|*.jpg|視頻文件|*.avi|所有文件|*.*";

                        //如果沒(méi)有選擇保存文件路徑就一直打開(kāi)保存框

                        while (true)

                        {

                            sfd.ShowDialog(this);

                            filePath = sfd.FileName;

                            if (string.IsNullOrEmpty(filePath))

                            {

                                continue;

                            }

                            else

                            {

                                break;

                            }

                        }                                        

                    }

                    else if (buffer[0] == 2) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是2,說(shuō)明接收的是震動(dòng)

                    {

                        ZD();

                    }

                }

            }

            catch { }

            

           

        }



        /// <summary>

        /// 顯示信息

        /// </summary>

        /// <param name="message"></param>

        private void ShowMsg(string message)

        {

            txtLog.AppendText(message + "\r\n");

        }


        /// <summary>

        /// 發(fā)送數(shù)據(jù)

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnSend_Click(object sender, EventArgs e)

        {

            try

            {

                byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);

                //獲得發(fā)送的信息時(shí)候,在數(shù)組前面加上一個(gè)字節(jié) 0

                List<byte> list = new List<byte>();

                list.Add(0);

                list.AddRange(buffer);

                //將泛型集合轉(zhuǎn)換為數(shù)組

                byte[] newBuffer = list.ToArray();

                //將了標(biāo)識(shí)字符的字節(jié)數(shù)組傳遞給客戶端

                socketSend.Send(newBuffer);

                txtMsg.Text = "";

            }

            catch{}          

        }  


        /// <summary>

        /// 選擇文件

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnSelect_Click(object sender, EventArgs e)

        {

            //打開(kāi)文件

            OpenFileDialog ofd = new OpenFileDialog();

            ofd.Title = "選擇要傳的文件";

            ofd.InitialDirectory = @"C:\Users\Administrator\Desktop";

            ofd.Filter = "文本文件|*.txt|圖片文件|*.jpg|視頻文件|*.avi|所有文件|*.*";

            ofd.ShowDialog();

            //得到選擇文件的路徑

            txtPath.Text = ofd.FileName;

        }


        /// <summary>

        /// 發(fā)送文件

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnSendFile_Click(object sender, EventArgs e)

        {       

            try

            {

                string filePath = txtPath.Text;

                if (string.IsNullOrEmpty(filePath))

                {

                    MessageBox.Show("請(qǐng)選擇文件");

                    return;

                }

                //讀取選擇的文件

                using (FileStream fsRead = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read))

                {

                    byte[] buffer = new byte[1024 * 1024 * 2];

                    int r = fsRead.Read(buffer, 0, buffer.Length);

                    //獲得發(fā)送的信息時(shí)候,在數(shù)組前面加上一個(gè)字節(jié) 1

                    List<byte> list = new List<byte>();

                    list.Add(1);

                    list.AddRange(buffer);

                    byte[] newBuffer = list.ToArray();

                    //將了標(biāo)識(shí)字符的字節(jié)數(shù)組傳遞給客戶端

                    socketSend.Send(newBuffer, 0, r + 1, SocketFlags.None);

                    txtPath.Text = "";

                }

            }

            catch{ }

        }


        /// <summary>

        /// 震動(dòng)

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btnZD_Click(object sender, EventArgs e)

        {        

            try

            {

                // 首字節(jié)是2說(shuō)明是震動(dòng)

                byte[] buffer = new byte[1];

                buffer[0] = 2;

                socketSend.Send(buffer);

            }

            catch{ }

        }


        /// <summary>

        /// 震動(dòng)

        /// </summary>

        private void ZD()

        {

            //獲取當(dāng)前窗體的坐標(biāo)

            Point point = this.Location;

            //反復(fù)給窗體坐標(biāo)復(fù)制一百次,達(dá)到震動(dòng)的效果

            for (int i = 0; i < 100; i++)

            {

                this.Location = new Point(point.X - 5, point.Y - 5);

                this.Location = new Point(point.X + 5, point.Y + 5);

            }

            this.Location = point;

        }

    }

}

1)傳輸類(lèi)型說(shuō)明以及全局變量


這些說(shuō)明以及全局變量,說(shuō)的也比較清楚,也不累贅了。

2)Socket通信服務(wù)端具體步驟:

(這些步驟都是根據(jù)第一個(gè)圖來(lái)的)

 (1)建立一個(gè)通信的Socket

/// <summary>

/// 建立連接

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btnStart_Click(object sender, EventArgs e)

{

    try

    {

        //創(chuàng)建負(fù)責(zé)通信的Socket

        socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        //獲取服務(wù)端的IP

        IPAddress ip = IPAddress.Parse(txtServer.Text.Trim());

        //獲取服務(wù)端的端口號(hào)

        IPEndPoint port = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));

        //獲得要連接的遠(yuǎn)程服務(wù)器應(yīng)用程序的IP地址和端口號(hào)

        socketSend.Connect(port);

        ShowMsg("連接成功");

        //新建線程,去接收客戶端發(fā)來(lái)的信息

        Thread td = new Thread(AcceptMgs);

        td.IsBackground = true;

        td.Start();

    }

    catch { }

}

在連接按鈕里,我們建立了Socket

由于客戶端會(huì)不停的去監(jiān)視接收服務(wù)端發(fā)來(lái)的信息,如果把這個(gè)工作放到主線程里,程序會(huì)出現(xiàn)假死的現(xiàn)象,所以這里給他放到一個(gè)新的線程里。

(2)接收信息

/// <summary>

/// 接收數(shù)據(jù)

/// </summary>

private void AcceptMgs()

{           

    try

    {

        /// <summary>

        /// 存儲(chǔ)大文件的大小

        /// </summary>

        long length = 0;

        long recive = 0; //接收的大文件總的字節(jié)數(shù)

        while (true)

        {

            byte[] buffer = new byte[1024 * 1024];

            int r = socketSend.Receive(buffer);

            if (r == 0)

            {

                break;

            }

            if (length > 0)  //判斷大文件是否已經(jīng)保存完

            {

                //保存接收的文件

                using (FileStream fsWrite = new FileStream(filePath, FileMode.Append, FileAccess.Write))

                {

                    fsWrite.Write(buffer, 0, r);

                    length -= r; //減去每次保存的字節(jié)數(shù)

                    ShowMsg(string.Format("{0}: 已接收:{1}/{2}", socketSend.RemoteEndPoint, recive-length, recive));

                    if (length <= 0)

                    {

                        ShowMsg(socketSend.RemoteEndPoint + ": 接收文件成功");

                    }

                    continue;

                }                        

            }

            if (buffer[0] == 0) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是0,說(shuō)明接收的字符串信息

            {

                string strMsg = Encoding.UTF8.GetString(buffer, 1, r - 1);

                ShowMsg(socketSend.RemoteEndPoint.ToString() + ": " + strMsg);

            }

            else if (buffer[0] == 1) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是1,說(shuō)明接收的是文件

            {

                length = int.Parse(Encoding.UTF8.GetString(buffer,1,r-1));

                recive = length;

                filePath = "";

                SaveFileDialog sfd = new SaveFileDialog();

                sfd.Title = "保存文件";

                sfd.InitialDirectory = @"C:\Users\Administrator\Desktop";

                sfd.Filter = "文本文件|*.txt|圖片文件|*.jpg|視頻文件|*.avi|所有文件|*.*";

                //如果沒(méi)有選擇保存文件路徑就一直打開(kāi)保存框

                while (true)

                {

                    sfd.ShowDialog(this);

                    filePath = sfd.FileName;

                    if (string.IsNullOrEmpty(filePath))

                    {

                        continue;

                    }

                    else

                    {

                        break;

                    }

                }                                        

            }

            else if (buffer[0] == 2) //如果接收的字節(jié)數(shù)組的第一個(gè)字節(jié)是2,說(shuō)明接收的是震動(dòng)

            {

                ZD();

            }

        }

    }

    catch { }

}

接收信息是會(huì)根據(jù)接收到字節(jié)數(shù)字的第一個(gè)字節(jié)來(lái)判斷接收到的是什么,如果接收的是個(gè)大文件,首先會(huì)接收大文件的大小,然后根據(jù)大小接收相同大小的字節(jié)數(shù)組追加保存到一個(gè)文件里去。

(3)發(fā)送數(shù)據(jù)(這里分發(fā)送字符串、文件(包含大文件)、震動(dòng))

發(fā)送字符串信息

/// <summary>

/// 發(fā)送數(shù)據(jù)

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btnSend_Click(object sender, EventArgs e)

{

    try

    {

        byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);

        //獲得發(fā)送的信息時(shí)候,在數(shù)組前面加上一個(gè)字節(jié) 0

        List<byte> list = new List<byte>();

        list.Add(0);

        list.AddRange(buffer);

        //將泛型集合轉(zhuǎn)換為數(shù)組

        byte[] newBuffer = list.ToArray();

        //將了標(biāo)識(shí)字符的字節(jié)數(shù)組傳遞給客戶端

        socketSend.Send(newBuffer);

        txtMsg.Text = "";

    }

    catch{}          

}

發(fā)送震動(dòng)

/// <summary>

/// 震動(dòng)

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btnZD_Click(object sender, EventArgs e)

{        

    try

    {

        // 首字節(jié)是2說(shuō)明是震動(dòng)

        byte[] buffer = new byte[1];

        buffer[0] = 2;

        socketSend.Send(buffer);

    }

    catch{ }

}

/// <summary>

/// 震動(dòng)

/// </summary>

private void ZD()

{

    //獲取當(dāng)前窗體的坐標(biāo)

    Point point = this.Location;

    //反復(fù)給窗體坐標(biāo)復(fù)制一百次,達(dá)到震動(dòng)的效果

    for (int i = 0; i < 100; i++)

    {

        this.Location = new Point(point.X - 5, point.Y - 5);

        this.Location = new Point(point.X + 5, point.Y + 5);

    }

    this.Location = point;

}

發(fā)送文件(不包含大文件)

首先要選擇文件

/// <summary>

/// 選擇文件

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btnSelect_Click(object sender, EventArgs e)

{

    //打開(kāi)文件

    OpenFileDialog ofd = new OpenFileDialog();

    ofd.Title = "選擇要傳的文件";

    ofd.InitialDirectory = @"C:\Users\Administrator\Desktop";

    ofd.Filter = "文本文件|*.txt|圖片文件|*.jpg|視頻文件|*.avi|所有文件|*.*";

    ofd.ShowDialog();

    //得到選擇文件的路徑

    txtPath.Text = ofd.FileName;

}

然后在發(fā)送文件

/// <summary>

/// 發(fā)送文件

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btnSendFile_Click(object sender, EventArgs e)

{       

    try

    {

        string filePath = txtPath.Text;

        if (string.IsNullOrEmpty(filePath))

        {

            MessageBox.Show("請(qǐng)選擇文件");

            return;

        }

        //讀取選擇的文件

        using (FileStream fsRead = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read))

        {

            byte[] buffer = new byte[1024 * 1024 * 2];

            int r = fsRead.Read(buffer, 0, buffer.Length);

            //獲得發(fā)送的信息時(shí)候,在數(shù)組前面加上一個(gè)字節(jié) 1

            List<byte> list = new List<byte>();

            list.Add(1);

            list.AddRange(buffer);

            byte[] newBuffer = list.ToArray();

            //將了標(biāo)識(shí)字符的字節(jié)數(shù)組傳遞給客戶端

            socketSend.Send(newBuffer, 0, r + 1, SocketFlags.None);

            txtPath.Text = "";

        }

    }

    catch{ }

}


該文章在 2021/3/3 12:26:08 編輯過(guò)

全部評(píng)論1

admin
2021年3月3日 12:26
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專(zhuān)業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車(chē)隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類(lèi)企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷(xiāo)售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved