C# Socket異步實現消息發送--附帶源碼


前言

看了一百遍,不如動手寫一遍。

Socket這塊使用不是特別熟悉,之前實現是公司有對應源碼改改能用。

但是不理解實現的過程和步驟,然后最近有時間自己寫個demo實現看看,熟悉熟悉Socket。

網上也有好的文章,結合別人的理接和自己實踐總算寫完了。。。

參考: https://www.cnblogs.com/sunev/ 實現

參考:https://blog.csdn.net/woshiyuanlei/article/details/47684221

          https://www.cnblogs.com/dotnet261010/p/6211900.html

理解握手過程,關閉時的握手過程(關閉的過程弄了半天,總算弄懂了意思)。

實現過程

總體包含:開啟,關閉,斷線重連(客戶端),內容發送。

說明:服務端和客戶端代碼基本一致,客戶端需要實時監聽服務端狀態,斷開時需要重連。

頁面效果圖:

服務端實現(實現不包含UI部分 最后面放所有代碼和下載地址)

給出一個指定的地址IP+Port,套接字類型初始化Socket

使用Bind方法進行關聯,Listen(10) 注釋: 掛起連接隊列的最大長度。我的通俗理接:你有一個女朋友這時你不能找別的,但是如果分手了就可以找別的,

BeginAccept包含一個異步的回調,獲取請求的Socket

var s_socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
s_socket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
s_socket.Listen(10);//同時連接的最大連接數
s_socket.BeginAccept(new AsyncCallback(Accept), s_socket);//獲取連接

ClientState,自己聲明的一個類用於接收數據(對應ReadCallback)和內部處理

Accept異步請求回調,當有Socket請求時會進去該回調,

EndAccept,我的理接為給當前Socket創建一個新的鏈接釋放掉 Listen

BeginReceive,包含一個消息回調(ReadCallback),只需給出指定長度數組接收Socket上傳的消息數據

BeginAccept,再次執行等待方法等待后續Socket連接

        /// <summary>
        /// 異步連接回調 獲取請求Socket
        /// </summary>
        /// <param name="ar">請求的Socket</param>
        private void Accept(IAsyncResult ar)
        {
            try
            {
                //獲取連接Socket 創建新的連接
                Socket myServer = ar.AsyncState as Socket;
                Socket service = myServer.EndAccept(ar);

                ClientState obj = new ClientState();
                obj.clientSocket = service;
                //接收連接Socket數據
                service.BeginReceive(obj.buffer, 0, ClientState.bufsize, SocketFlags.None, new AsyncCallback(ReadCallback), obj);
                myServer.BeginAccept(new AsyncCallback(Accept), myServer);//等待下一個連接
            }
            catch (Exception ex)
            {
                Console.WriteLine("服務端關閉"+ex.Message+" "+ex.StackTrace);
            }
        }

EndReceive,通俗理接買東西的時候老板已經打包好了,付錢走人。

BeginReceive,當數據處理完成之后,和Socket連接一樣需再次執行獲取下次數據

        /// <summary>
        /// 數據接收
        /// </summary>
        /// <param name="ar">請求的Socket</param>
        private void ReadCallback(IAsyncResult ar)
        {
            //獲取並保存
            ClientState obj = ar.AsyncState as ClientState;
            Socket c_socket = obj.clientSocket;
            int bytes = c_socket.EndReceive(ar);                    
            //接收完成 重新給出buffer接收
            obj.buffer = new byte[ClientState.bufsize];
            c_socket.BeginReceive(obj.buffer, 0, ClientState.bufsize, 0, new AsyncCallback(ReadCallback), obj);
         }

Send,消息發送比較簡單,將發送的數組轉成數組的形式進行發送

        /// <summary>
        /// 發送消息
        /// </summary>
        /// <param name="c_socket">指定客戶端socket</param>
        /// <param name="by">內容數組</param>
        private void Send(Socket c_socket, byte[] by)
        {
               //發送
                c_socket.BeginSend(by, 0, by.Length, SocketFlags.None, asyncResult =>
                {
                    try
                    {
                        //完成消息發送
                        int len = c_socket.EndSend(asyncResult);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("error ex=" + ex.Message + " " + ex.StackTrace);
                    }
                }, null);
        }

 

客戶端實現(實現不包含UI部分 最后面放所有代碼和下載地址)

相對於服務端差別不大,只是需要在鏈接之后增加一個監聽機制,進行斷線重連,我寫的這個比較粗糙。

BeginConnect,使用指定的地址ip+port進新一個異步的鏈接

Connect,鏈接回調

ConnectionResult,初始值為-2 在消息接收(可檢測服務端斷開),鏈接(鏈接失敗)重新賦值然后判斷是否為錯誤碼然后重連

        /// <summary>
        /// 連接Socket
        /// </summary>
        public void Start()
        {
            try
            {
                var endPoint = new IPEndPoint(IPAddress.Parse(ip), port);
                c_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                c_socket.BeginConnect(endPoint, new AsyncCallback(Connect), c_socket);//鏈接服務端
                th_socket = new Thread(MonitorSocker);//監聽線程
                th_socket.IsBackground = true;
                th_socket.Start();           
           }
           catch (SocketException ex)
           {
                Console.WriteLine("error ex=" + ex.Message + " " + ex.StackTrace);
            }
        }

        //監聽Socket
        void MonitorSocker()
        {
            while (true)
            {
                if (ConnectionResult != 0 && ConnectionResult != -2)//通過錯誤碼判斷
                {
                    Start();
                }
                Thread.Sleep(1000);
            }
        }

 

Connec鏈接部分

        /// <summary>
        /// 連接服務端
        /// </summary>
        /// <param name="ar"></param>
        private void Connect(IAsyncResult ar)
        {
            try
            {
                ServiceState obj = new ServiceState();
                Socket client = ar.AsyncState as Socket;
                obj.serviceSocket = client;
                //獲取服務端信息
                client.EndConnect(ar);
                //接收連接Socket數據 
                client.BeginReceive(obj.buffer, 0, ServiceState.bufsize, SocketFlags.None, new AsyncCallback(ReadCallback), obj);
catch (SocketException ex)
            {
                ConnectionResult = ex.ErrorCode;
                Console.WriteLine(ex.Message + " " + ex.StackTrace);
            }
        }

 

整體數據發送和實現部分

聲明一個指定的類,給出指定的標識,方便數據處理,

在發送文字消息,圖片消息,震動時需要對應的判斷其實最簡便的方法是直接發送一個XML報文過去直接解析,

也可以采用在頭部信息里面直接給出傳送類型。

數組中給出了一個0-15的信息頭

0-3 標識碼,確認身份

4-7 總長度,總體長度可用於接收時判斷所需長度

8-11 內容長度,判斷內容是否接收完成

12-15 補0,1111(震動) 2222(圖片數據,圖片這塊為了接收圖片名稱所以采用XML報文形式發送)

16開始為內容

    /// <summary>
    /// 0-3 標識碼 4-7 總長度 8-11 內容長度 12-15補0 16開始為內容
    /// </summary>
    public class SendSocket
    {
        /// <summary>
        /// 頭 標識8888
        /// </summary>
        byte[] Header = new byte[4] { 0x08, 0x08, 0x08, 0x08 };

        /// <summary>
        /// 文本消息
        /// </summary>
        public string Message;

        /// <summary>
        /// 是否發送震動
        /// </summary>
        public bool SendShake = false;

        /// <summary>
        /// 是否發送圖片
        /// </summary>
        public bool SendImg = false;

        /// <summary>
        /// 圖片名稱
        /// </summary>
        public string ImgName;

        /// <summary>
        /// 圖片數據
        /// </summary>
        public string ImgBase64;
        /// <summary>
        /// 組成特定格式的byte數據
        /// 12-15 為指定發送內容 1111(震動) 2222(圖片數據)
        /// </summary>
        /// <returns>特定格式的byte</returns>
        public byte[] ToArray()
        {
            if (SendImg)//是否發送圖片
            {
                //組成XML接收 可以接收相關圖片數據
                StringBuilder xmlResult = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
                xmlResult.Append("<ImgMessage>");
                xmlResult.AppendFormat("<ImgName>{0}</ImgName>", ImgName);
                xmlResult.AppendFormat("<ImgBase64>{0}</ImgBase64>", ImgBase64);
                xmlResult.Append("</ImgMessage>");
                Message = xmlResult.ToString();
            }

            byte[] byteData = Encoding.UTF8.GetBytes(Message);//內容
            int count = 16 + byteData.Length;//總長度
            byte[] SendBy = new byte[count];
            Array.Copy(Header, 0, SendBy, 0, Header.Length);//添加頭

            byte[] CountBy = BitConverter.GetBytes(count);
            Array.Copy(CountBy, 0, SendBy, 4, CountBy.Length);//總長度

            byte[] ContentBy = BitConverter.GetBytes(byteData.Length);
            Array.Copy(ContentBy, 0, SendBy, 8, ContentBy.Length);//內容長度

            if (SendShake)//發動震動
            {
                var shakeBy = new byte[4] { 1, 1, 1, 1 };
                Array.Copy(shakeBy, 0, SendBy, 12, shakeBy.Length);//震動
            }

            if (SendImg)//發送圖片
            {
                var imgBy = new byte[4] { 2, 2, 2, 2 };
                Array.Copy(imgBy, 0, SendBy, 12, imgBy.Length);//圖片
            }

            Array.Copy(byteData, 0, SendBy, 16, byteData.Length);//內容
            return SendBy;
        }
    }

 

代碼:

服務端:

窗體(UI)代碼:

namespace SocketService
{
    partial class Form1
    {
        /// <summary>
        /// 必需的設計器變量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清理所有正在使用的資源。
        /// </summary>
        /// <param name="disposing">如果應釋放托管資源,為 true;否則為 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows 窗體設計器生成的代碼

        /// <summary>
        /// 設計器支持所需的方法 - 不要修改
        /// 使用代碼編輯器修改此方法的內容。
        /// </summary>
        private void InitializeComponent()
        {
            this.label1 = new System.Windows.Forms.Label();
            this.txt_ip = new System.Windows.Forms.TextBox();
            this.txt_port = new System.Windows.Forms.TextBox();
            this.label2 = new System.Windows.Forms.Label();
            this.btn_StartSocket = new System.Windows.Forms.Button();
            this.txt_Monitor = new System.Windows.Forms.TextBox();
            this.label3 = new System.Windows.Forms.Label();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.btn_SendImg = new System.Windows.Forms.Button();
            this.btn_SendShake = new System.Windows.Forms.Button();
            this.btn_SendMes = new System.Windows.Forms.Button();
            this.txt_Mes = new System.Windows.Forms.TextBox();
            this.label4 = new System.Windows.Forms.Label();
            this.dataGridView1 = new System.Windows.Forms.DataGridView();
            this.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.Column2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.groupBox2 = new System.Windows.Forms.GroupBox();
            this.lab_ImgName = new System.Windows.Forms.Label();
            this.pictureBox1 = new System.Windows.Forms.PictureBox();
            this.listBox_Mes = new System.Windows.Forms.ListBox();
            this.listBox_attribute = new System.Windows.Forms.ListBox();
            this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
            this.btn_Stop = new System.Windows.Forms.Button();
            this.label5 = new System.Windows.Forms.Label();
            this.label6 = new System.Windows.Forms.Label();
            this.label7 = new System.Windows.Forms.Label();
            this.groupBox1.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
            this.groupBox2.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
            this.SuspendLayout();
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(13, 13);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(17, 12);
            this.label1.TabIndex = 0;
            this.label1.Text = "IP";
            // 
            // txt_ip
            // 
            this.txt_ip.Location = new System.Drawing.Point(36, 10);
            this.txt_ip.Name = "txt_ip";
            this.txt_ip.Size = new System.Drawing.Size(100, 21);
            this.txt_ip.TabIndex = 1;
            this.txt_ip.Text = "127.0.0.1";
            // 
            // txt_port
            // 
            this.txt_port.Location = new System.Drawing.Point(183, 10);
            this.txt_port.Name = "txt_port";
            this.txt_port.Size = new System.Drawing.Size(100, 21);
            this.txt_port.TabIndex = 3;
            this.txt_port.Text = "9999";
            // 
            // label2
            // 
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(148, 15);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(29, 12);
            this.label2.TabIndex = 2;
            this.label2.Text = "端口";
            // 
            // btn_StartSocket
            // 
            this.btn_StartSocket.Location = new System.Drawing.Point(307, 8);
            this.btn_StartSocket.Name = "btn_StartSocket";
            this.btn_StartSocket.Size = new System.Drawing.Size(75, 23);
            this.btn_StartSocket.TabIndex = 4;
            this.btn_StartSocket.Text = "開始監聽";
            this.btn_StartSocket.UseVisualStyleBackColor = true;
            this.btn_StartSocket.Click += new System.EventHandler(this.btn_StartSocket_Click);
            // 
            // txt_Monitor
            // 
            this.txt_Monitor.Location = new System.Drawing.Point(460, 8);
            this.txt_Monitor.Name = "txt_Monitor";
            this.txt_Monitor.ReadOnly = true;
            this.txt_Monitor.Size = new System.Drawing.Size(155, 21);
            this.txt_Monitor.TabIndex = 6;
            // 
            // label3
            // 
            this.label3.AutoSize = true;
            this.label3.Location = new System.Drawing.Point(401, 11);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(53, 12);
            this.label3.TabIndex = 5;
            this.label3.Text = "正在監聽";
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.Add(this.btn_SendImg);
            this.groupBox1.Controls.Add(this.btn_SendShake);
            this.groupBox1.Controls.Add(this.btn_SendMes);
            this.groupBox1.Controls.Add(this.txt_Mes);
            this.groupBox1.Controls.Add(this.label4);
            this.groupBox1.Controls.Add(this.dataGridView1);
            this.groupBox1.Location = new System.Drawing.Point(13, 68);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(681, 275);
            this.groupBox1.TabIndex = 8;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "客戶端連接列表";
            // 
            // btn_SendImg
            // 
            this.btn_SendImg.Location = new System.Drawing.Point(466, 246);
            this.btn_SendImg.Name = "btn_SendImg";
            this.btn_SendImg.Size = new System.Drawing.Size(75, 23);
            this.btn_SendImg.TabIndex = 11;
            this.btn_SendImg.Text = "發送圖片";
            this.btn_SendImg.UseVisualStyleBackColor = true;
            this.btn_SendImg.Click += new System.EventHandler(this.btn_SendImg_Click);
            // 
            // btn_SendShake
            // 
            this.btn_SendShake.Location = new System.Drawing.Point(380, 246);
            this.btn_SendShake.Name = "btn_SendShake";
            this.btn_SendShake.Size = new System.Drawing.Size(75, 23);
            this.btn_SendShake.TabIndex = 10;
            this.btn_SendShake.Text = "發送震動";
            this.btn_SendShake.UseVisualStyleBackColor = true;
            this.btn_SendShake.Click += new System.EventHandler(this.btn_SendShake_Click);
            // 
            // btn_SendMes
            // 
            this.btn_SendMes.Location = new System.Drawing.Point(294, 246);
            this.btn_SendMes.Name = "btn_SendMes";
            this.btn_SendMes.Size = new System.Drawing.Size(75, 23);
            this.btn_SendMes.TabIndex = 9;
            this.btn_SendMes.Text = "發送";
            this.btn_SendMes.UseVisualStyleBackColor = true;
            this.btn_SendMes.Click += new System.EventHandler(this.btn_SendMes_Click);
            // 
            // txt_Mes
            // 
            this.txt_Mes.Location = new System.Drawing.Point(294, 50);
            this.txt_Mes.Multiline = true;
            this.txt_Mes.Name = "txt_Mes";
            this.txt_Mes.Size = new System.Drawing.Size(368, 190);
            this.txt_Mes.TabIndex = 2;
            // 
            // label4
            // 
            this.label4.AutoSize = true;
            this.label4.Location = new System.Drawing.Point(292, 35);
            this.label4.Name = "label4";
            this.label4.Size = new System.Drawing.Size(53, 12);
            this.label4.TabIndex = 1;
            this.label4.Text = "消息輸入";
            // 
            // dataGridView1
            // 
            this.dataGridView1.AllowUserToOrderColumns = true;
            this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
            this.Column1,
            this.Column2});
            this.dataGridView1.Location = new System.Drawing.Point(7, 35);
            this.dataGridView1.Name = "dataGridView1";
            this.dataGridView1.RowTemplate.Height = 23;
            this.dataGridView1.Size = new System.Drawing.Size(249, 234);
            this.dataGridView1.TabIndex = 0;
            // 
            // Column1
            // 
            this.Column1.HeaderText = "IP";
            this.Column1.Name = "Column1";
            // 
            // Column2
            // 
            this.Column2.HeaderText = "Port";
            this.Column2.Name = "Column2";
            // 
            // groupBox2
            // 
            this.groupBox2.Controls.Add(this.label7);
            this.groupBox2.Controls.Add(this.label6);
            this.groupBox2.Controls.Add(this.label5);
            this.groupBox2.Controls.Add(this.lab_ImgName);
            this.groupBox2.Controls.Add(this.pictureBox1);
            this.groupBox2.Controls.Add(this.listBox_Mes);
            this.groupBox2.Controls.Add(this.listBox_attribute);
            this.groupBox2.Location = new System.Drawing.Point(20, 349);
            this.groupBox2.Name = "groupBox2";
            this.groupBox2.Size = new System.Drawing.Size(898, 293);
            this.groupBox2.TabIndex = 9;
            this.groupBox2.TabStop = false;
            this.groupBox2.Text = "接收客戶端消息";
            // 
            // lab_ImgName
            // 
            this.lab_ImgName.AutoSize = true;
            this.lab_ImgName.Location = new System.Drawing.Point(443, 265);
            this.lab_ImgName.Name = "lab_ImgName";
            this.lab_ImgName.Size = new System.Drawing.Size(0, 12);
            this.lab_ImgName.TabIndex = 12;
            // 
            // pictureBox1
            // 
            this.pictureBox1.Location = new System.Drawing.Point(440, 37);
            this.pictureBox1.Name = "pictureBox1";
            this.pictureBox1.Size = new System.Drawing.Size(208, 220);
            this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
            this.pictureBox1.TabIndex = 3;
            this.pictureBox1.TabStop = false;
            // 
            // listBox_Mes
            // 
            this.listBox_Mes.FormattingEnabled = true;
            this.listBox_Mes.ItemHeight = 12;
            this.listBox_Mes.Location = new System.Drawing.Point(6, 37);
            this.listBox_Mes.Name = "listBox_Mes";
            this.listBox_Mes.Size = new System.Drawing.Size(428, 220);
            this.listBox_Mes.TabIndex = 2;
            // 
            // listBox_attribute
            // 
            this.listBox_attribute.FormattingEnabled = true;
            this.listBox_attribute.ItemHeight = 12;
            this.listBox_attribute.Location = new System.Drawing.Point(654, 37);
            this.listBox_attribute.Name = "listBox_attribute";
            this.listBox_attribute.Size = new System.Drawing.Size(202, 220);
            this.listBox_attribute.TabIndex = 1;
            // 
            // openFileDialog1
            // 
            this.openFileDialog1.FileName = "openFileDialog1";
            // 
            // btn_Stop
            // 
            this.btn_Stop.Location = new System.Drawing.Point(632, 8);
            this.btn_Stop.Name = "btn_Stop";
            this.btn_Stop.Size = new System.Drawing.Size(75, 23);
            this.btn_Stop.TabIndex = 11;
            this.btn_Stop.Text = "關閉監聽";
            this.btn_Stop.UseVisualStyleBackColor = true;
            this.btn_Stop.Click += new System.EventHandler(this.btn_Stop_Click);
            // 
            // label5
            // 
            this.label5.AutoSize = true;
            this.label5.Location = new System.Drawing.Point(6, 17);
            this.label5.Name = "label5";
            this.label5.Size = new System.Drawing.Size(77, 12);
            this.label5.TabIndex = 12;
            this.label5.Text = "接收消息顯示";
            // 
            // label6
            // 
            this.label6.AutoSize = true;
            this.label6.Location = new System.Drawing.Point(438, 22);
            this.label6.Name = "label6";
            this.label6.Size = new System.Drawing.Size(77, 12);
            this.label6.TabIndex = 13;
            this.label6.Text = "接收圖片顯示";
            // 
            // label7
            // 
            this.label7.AutoSize = true;
            this.label7.Location = new System.Drawing.Point(652, 22);
            this.label7.Name = "label7";
            this.label7.Size = new System.Drawing.Size(53, 12);
            this.label7.TabIndex = 14;
            this.label7.Text = "數據顯示";
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(930, 645);
            this.Controls.Add(this.btn_Stop);
            this.Controls.Add(this.groupBox2);
            this.Controls.Add(this.groupBox1);
            this.Controls.Add(this.txt_Monitor);
            this.Controls.Add(this.label3);
            this.Controls.Add(this.btn_StartSocket);
            this.Controls.Add(this.txt_port);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.txt_ip);
            this.Controls.Add(this.label1);
            this.Name = "Form1";
            this.Text = "服務端";
            this.groupBox1.ResumeLayout(false);
            this.groupBox1.PerformLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
            this.groupBox2.ResumeLayout(false);
            this.groupBox2.PerformLayout();
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.TextBox txt_ip;
        private System.Windows.Forms.TextBox txt_port;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.Button btn_StartSocket;
        private System.Windows.Forms.TextBox txt_Monitor;
        private System.Windows.Forms.Label label3;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.Button btn_SendShake;
        private System.Windows.Forms.Button btn_SendMes;
        private System.Windows.Forms.TextBox txt_Mes;
        private System.Windows.Forms.Label label4;
        private System.Windows.Forms.DataGridView dataGridView1;
        private System.Windows.Forms.GroupBox groupBox2;
        private System.Windows.Forms.ListBox listBox_attribute;
        private System.Windows.Forms.DataGridViewTextBoxColumn Column1;
        private System.Windows.Forms.DataGridViewTextBoxColumn Column2;
        private System.Windows.Forms.ListBox listBox_Mes;
        private System.Windows.Forms.PictureBox pictureBox1;
        private System.Windows.Forms.Button btn_SendImg;
        private System.Windows.Forms.OpenFileDialog openFileDialog1;
        private System.Windows.Forms.Label lab_ImgName;
        private System.Windows.Forms.Button btn_Stop;
        private System.Windows.Forms.Label label7;
        private System.Windows.Forms.Label label6;
        private System.Windows.Forms.Label label5;
    }
}
View Code

運行代碼:

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

namespace SocketService
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        #region 參數聲明
        /// <summary>
        /// 字典 IP加客戶端狀態
        /// </summary>
        static Dictionary<string, ClientState> dic_ip = new Dictionary<string, ClientState>();
        /// <summary>
        /// 服務端啟動的Socket
        /// </summary>
        Socket s_socket;
        #endregion

        /// <summary>
        /// 開啟監聽
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_StartSocket_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(this.txt_ip.Text.Trim()) && string.IsNullOrWhiteSpace(this.txt_port.Text.Trim()) && !string.IsNullOrWhiteSpace(this.txt_Monitor.Text.Trim()))
            {
                MessageBox.Show("輸入不符合或已在監聽");
                return;
            }

            //獲取IP PORT異步連接Socket
            string ip = this.txt_ip.Text.Trim();
            int port = int.Parse(this.txt_port.Text.Trim());
            s_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                s_socket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
                s_socket.Listen(1);//同時連接的最大連接數
                s_socket.BeginAccept(new AsyncCallback(Accept), s_socket);//獲取連接

                this.txt_Monitor.Text = ip + ":" + port;
                this.txt_ip.Enabled = false;
                this.txt_port.Enabled = false;
            }
            catch (Exception ex)
            {
                Console.WriteLine("error ex=" + ex.Message + " " + ex.StackTrace);
            }
        }

        /// <summary>
        /// 異步連接回調 獲取請求Socket 添加信息到控件
        /// </summary>
        /// <param name="ar"></param>
        private void Accept(IAsyncResult ar)
        {
            try
            {
                //獲取連接Socket 創建新的連接
                Socket myServer = ar.AsyncState as Socket;
                Socket service = myServer.EndAccept(ar);

                #region 內部邏輯 UI處理部分
                ClientState obj = new ClientState();
                obj.clientSocket = service;

                //添加到字典
                dic_ip.Add(service.RemoteEndPoint.ToString(), obj);
                var point = service.RemoteEndPoint.ToString().Split(':');
                this.BeginInvoke((MethodInvoker)delegate ()
                {
                    //獲取IP 端口添加到控件
                    int index = this.dataGridView1.Rows.Add();
                    dataGridView1.Rows[index].Cells[0].Value = point[0];
                    dataGridView1.Rows[index].Cells[1].Value = point[1];
                });
                #endregion

                //接收連接Socket數據
                service.BeginReceive(obj.buffer, 0, ClientState.bufsize, SocketFlags.None, new AsyncCallback(ReadCallback), obj);
                myServer.BeginAccept(new AsyncCallback(Accept), myServer);//等待下一個連接
            }
            catch (Exception ex)
            {
                Console.WriteLine("服務端關閉"+ex.Message+" "+ex.StackTrace);
            }
        }

        /// <summary>
        /// 發送消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_SendMes_Click(object sender, EventArgs e)
        {
            try
            {
                var key = dataGridView1.Rows[dataGridView1.CurrentRow.Index].Cells[0].Value + ":" + dataGridView1.Rows[dataGridView1.CurrentRow.Index].Cells[1].Value;
                SendSocket send = new SendSocket() { Message = this.txt_Mes.Text.Trim() };
                Send(dic_ip[key].clientSocket, send.ToArray());
            }
            catch (Exception ex)
            {
                MessageBox.Show("error ex=" + ex.Message + " " + ex.StackTrace);
            }
        }

        /// <summary>
        /// 發送震動
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_SendShake_Click(object sender, EventArgs e)
        {
            //根據選中的IP端口 獲取對應客戶端Socket
            var key = dataGridView1.Rows[dataGridView1.CurrentRow.Index].Cells[0].Value + ":" + dataGridView1.Rows[dataGridView1.CurrentRow.Index].Cells[1].Value;
            if (dic_ip.ContainsKey(key))
            {
                SendSocket send = new SendSocket()
                {
                    SendShake = true,
                    Message = "震動",
                };
                Send(dic_ip[key].clientSocket, send.ToArray());
            }
            else
            {
                MessageBox.Show("選中數據無效,找不到客戶端");
            }
        }

        /// <summary>
        /// 發送圖片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_SendImg_Click(object sender, EventArgs e)
        {
            var key = dataGridView1.Rows[dataGridView1.CurrentRow.Index].Cells[0].Value + ":" + dataGridView1.Rows[dataGridView1.CurrentRow.Index].Cells[1].Value;
            if (dic_ip.ContainsKey(key))
            {
                //初始化一個OpenFileDialog類
                OpenFileDialog fileDialog = new OpenFileDialog();

                //判斷用戶是否正確的選擇了文件
                if (fileDialog.ShowDialog() == DialogResult.OK)
                {
                    string extension = Path.GetExtension(fileDialog.FileName);
                    string[] str = new string[] { ".gif", ".jpge", ".jpg", "bmp" };//准許上傳格式
                    if (!((IList)str).Contains(extension))
                    {
                        MessageBox.Show("僅能上傳gif,jpge,jpg,bmp格式的圖片!");
                    }
                    FileInfo fileInfo = new FileInfo(fileDialog.FileName);
                    if (fileInfo.Length > 26214400)//不能大於25 
                    {
                        MessageBox.Show("圖片不能大於25M");
                    }

                    //將圖片轉成base64發送
                    SendSocket send = new SendSocket()
                    {
                        SendImg = true,
                        ImgName = fileDialog.SafeFileName,
                    };
                    using (FileStream file = new FileStream(fileDialog.FileName, FileMode.Open, FileAccess.Read))
                    {
                        var imgby = new byte[file.Length];
                        file.Read(imgby, 0, imgby.Length);
                        send.ImgBase64 = Convert.ToBase64String(imgby);
                    }

                    Send(dic_ip[key].clientSocket, send.ToArray());
                }
            }
            else
            {
                MessageBox.Show("請正確選擇,選中客戶端不存在");
            }
        }

        #region Socket 發送和接收
        /// <summary>
        /// 發送消息
        /// </summary>
        /// <param name="s_socket">指定客戶端socket</param>
        /// <param name="message">發送消息</param>
        /// <param name="Shake">發送消息</param>
        private void Send(Socket c_socket, byte[] by)
        {
            try
            {
                //發送
                c_socket.BeginSend(by, 0, by.Length, SocketFlags.None, asyncResult =>
                {
                    try
                    {
                        //完成消息發送
                        int len = c_socket.EndSend(asyncResult);
                    }
                    catch (Exception ex)
                    {
                        if (c_socket != null)
                        {
                            c_socket.Close();
                            c_socket = null;
                        }
                        Console.WriteLine("error ex=" + ex.Message + " " + ex.StackTrace);
                    }
                }, null);
                this.txt_Mes.Text = null;
            }
            catch (Exception ex)
            {
                if (c_socket != null)
                {
                    c_socket.Close();
                    c_socket = null;
                }
                Console.WriteLine("error ex=" + ex.Message + " " + ex.StackTrace);
            }
        }

        /// <summary>
        /// 數據接收
        /// </summary>
        /// <param name="ar">請求的Socket</param>
        private void ReadCallback(IAsyncResult ar)
        {
            //獲取並保存
            ClientState obj = ar.AsyncState as ClientState;
            Socket c_socket = obj.clientSocket;
            try
            {
                int bytes = c_socket.EndReceive(ar);
                #region 接收數據
                if (bytes == 16)
                {
                    byte[] buf = obj.buffer;
                    //判斷頭部是否正確 標識0-3 8888
                    if (buf[0] == 8 && buf[1] == 8 && buf[2] == 8 && buf[3] == 8)
                    {
                        //判斷是否為震動 標識12-15 1111
                        if (buf[12] == 1 && buf[13] == 1 && buf[14] == 1 && buf[15] == 1)
                        {
                            //實現震動效果
                            this.BeginInvoke((MethodInvoker)delegate ()
                            {
                                int x = 5, y = 10;
                                for (int i = 0; i < 5; i++)
                                {
                                    this.Left += x;
                                    Thread.Sleep(y);
                                    this.Top += x;
                                    Thread.Sleep(y);
                                    this.Left -= x;
                                    Thread.Sleep(y);
                                    this.Top -= x;
                                    Thread.Sleep(y);
                                }
                            });
                        }

                        else
                        {
                            int totalLength = BitConverter.ToInt32(buf, 4);//獲取數據總長度
                            //獲取內容長度
                            int contentLength = BitConverter.ToInt32(buf, 8);
                            obj.buffer = new byte[contentLength];
                            int readDataPtr = 0;
                            while (readDataPtr < contentLength)//判斷內容是否接收完成
                            {
                                var re = c_socket.Receive(obj.buffer, readDataPtr, contentLength - readDataPtr, SocketFlags.None);//接收內容
                                readDataPtr += re;
                            }

                            //轉換顯示 UTF8
                            var str = Encoding.UTF8.GetString(obj.buffer, 0, contentLength);

                            if (buf[12] == 2 && buf[13] == 2 && buf[14] == 2 && buf[15] == 2)
                            {
                                #region 解析報文
                                //顯示到listbox 
                                this.BeginInvoke((MethodInvoker)delegate ()
                                {
                                    var time = DateTime.Now.ToString();
                                    this.listBox_Mes.Items.Add(time + "   " + c_socket.RemoteEndPoint.ToString());
                                    this.listBox_Mes.Items.Add("接收到圖片");
                                    this.listBox_attribute.Items.Add(DateTime.Now.ToString());
                                    this.listBox_attribute.Items.Add("數據總長度 " + totalLength + " 內容長度 " + contentLength);
                                });
                                try
                                {
                                    //解析XML 獲取圖片名稱和BASE64字符串
                                    XmlDocument document = new XmlDocument();
                                    document.LoadXml(str);

                                    XmlNodeList root = document.SelectNodes("/ImgMessage");
                                    string imgNmae = string.Empty, imgBase64 = string.Empty;
                                    foreach (XmlElement node in root)
                                    {
                                        imgNmae = node.GetElementsByTagName("ImgName")[0].InnerText;
                                        imgBase64 = node.GetElementsByTagName("ImgBase64")[0].InnerText;
                                    }

                                    //BASE64轉成圖片
                                    byte[] imgbuf = Convert.FromBase64String(imgBase64);
                                    using (System.IO.MemoryStream m_Str = new System.IO.MemoryStream(imgbuf))
                                    {
                                        using (Bitmap bit = new Bitmap(m_Str))
                                        {
                                            //保存到本地並上屏
                                            var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, imgNmae);
                                            bit.Save(path);
                                            pictureBox1.BeginInvoke((MethodInvoker)delegate ()
                                            {
                                                lab_ImgName.Text = imgNmae;
                                                pictureBox1.ImageLocation = path;
                                            });
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Console.WriteLine(ex.Message + " " + ex.StackTrace);
                                }
                                #endregion
                            }
                            else
                            {
                                //顯示到listbox 
                                this.BeginInvoke((MethodInvoker)delegate ()
                                {
                                    var time = DateTime.Now.ToString();
                                    this.listBox_Mes.Items.Add(time + "   " + c_socket.RemoteEndPoint.ToString());
                                    this.listBox_Mes.Items.Add(str);
                                    this.listBox_attribute.Items.Add(DateTime.Now.ToString());
                                    this.listBox_attribute.Items.Add("數據總長度 " + totalLength + " 內容長度 " + contentLength);
                                });
                            }
                        }
                    }
                    //接收完成 重新給出buffer接收
                    obj.buffer = new byte[ClientState.bufsize];
                    c_socket.BeginReceive(obj.buffer, 0, ClientState.bufsize, 0, new AsyncCallback(ReadCallback), obj);
                }
                else
                {
                    UpdateControls(c_socket);
                }
                #endregion
            }
            catch (Exception ex)
            {
                UpdateControls(c_socket);
            }
        }

        /// <summary>
        /// 關閉指定客戶端 更新控件
        /// </summary>
        /// <param name="socket"></param>
        public void UpdateControls(Socket socket)
        {
            dic_ip.Remove(socket.RemoteEndPoint.ToString());
            List<int> list = new List<int>();
            for (int i = 0; i < dataGridView1.RowCount; i++)
            {

                var val = dataGridView1.Rows[i].Cells[0].Value + ":" + dataGridView1.Rows[i].Cells[1].Value;
                if (val != null && val.ToString() == socket.RemoteEndPoint.ToString())
                {
                    list.Add(i);
                }
            }

            this.BeginInvoke((MethodInvoker)delegate ()
            {
                foreach (var item in list)
                {
                    dataGridView1.Rows.Remove(dataGridView1.Rows[item]);
                }
            });
            socket.Close();
            socket.Dispose();
        }
        #endregion

        /// <summary>
        /// 停止
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Stop_Click(object sender, EventArgs e)
        {
            s_socket.Close();
            this.txt_ip.Enabled = true;
            this.txt_port.Enabled = true;
            this.txt_Monitor.Text = null;
        }
    }
}
View Code

聲明的類:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace SocketService
{
    /// <summary>
    /// 接收消息
    /// </summary>
    public class ClientState
    {
        public Socket clientSocket = null;
        public const int bufsize = 16;
        public byte[] buffer = new byte[bufsize];
        public StringBuilder str = new StringBuilder();
    }

    /// <summary>
    /// 顯示客戶端IP 端口
    /// </summary>
    public class ClientClass
    {
        public string IP { get; set; }
        public string Port { get; set; }
    }

    /// <summary>
    /// 0-3 標識碼 4-7 總長度 8-11 內容長度 12-15補0 16開始為內容
    /// </summary>
    public class SendSocket
    {
        /// <summary>
        /// 頭 標識8888
        /// </summary>
        byte[] Header = new byte[4] { 0x08, 0x08, 0x08, 0x08 };

        /// <summary>
        /// 文本消息
        /// </summary>
        public string Message;

        /// <summary>
        /// 是否發送震動
        /// </summary>
        public bool SendShake = false;

        /// <summary>
        /// 是否發送圖片
        /// </summary>
        public bool SendImg = false;

        /// <summary>
        /// 圖片名稱
        /// </summary>
        public string ImgName;

        /// <summary>
        /// 圖片數據
        /// </summary>
        public string ImgBase64;
        /// <summary>
        /// 組成特定格式的byte數據
        /// 12-15 為指定發送內容 1111(震動) 2222(圖片數據)
        /// </summary>
        /// <param name="mes">文本消息</param>
        /// <param name="Shake">震動</param>
        /// <param name="Img">圖片</param>
        /// <returns>特定格式的byte</returns>
        public byte[] ToArray()
        {
            if (SendImg)//是否發送圖片
            {
                //組成XML接收 可以接收相關圖片數據
                StringBuilder xmlResult = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
                xmlResult.Append("<ImgMessage>");
                xmlResult.AppendFormat("<ImgName>{0}</ImgName>", ImgName);
                xmlResult.AppendFormat("<ImgBase64>{0}</ImgBase64>", ImgBase64);
                xmlResult.Append("</ImgMessage>");
                Message = xmlResult.ToString();
            }

            byte[] byteData = Encoding.UTF8.GetBytes(Message);//內容
            int count = 16 + byteData.Length;//總長度
            byte[] SendBy = new byte[count];
            Array.Copy(Header, 0, SendBy, 0, Header.Length);//添加頭

            byte[] CountBy = BitConverter.GetBytes(count);
            Array.Copy(CountBy, 0, SendBy, 4, CountBy.Length);//總長度

            byte[] ContentBy = BitConverter.GetBytes(byteData.Length);
            Array.Copy(ContentBy, 0, SendBy, 8, ContentBy.Length);//內容長度

            if (SendShake)//發動震動
            {
                var shakeBy = new byte[4] { 1, 1, 1, 1 };
                Array.Copy(shakeBy, 0, SendBy, 12, shakeBy.Length);//震動
            }

            if (SendImg)//發送圖片
            {
                var imgBy = new byte[4] { 2, 2, 2, 2 };
                Array.Copy(imgBy, 0, SendBy, 12, imgBy.Length);//圖片
            }

            Array.Copy(byteData, 0, SendBy, 16, byteData.Length);//內容
            return SendBy;
        }
    }
}
View Code

客戶端

窗體(UI)代碼:

namespace SocketClient
{
    partial class Form1
    {
        /// <summary>
        /// 必需的設計器變量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清理所有正在使用的資源。
        /// </summary>
        /// <param name="disposing">如果應釋放托管資源,為 true;否則為 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows 窗體設計器生成的代碼

        /// <summary>
        /// 設計器支持所需的方法 - 不要修改
        /// 使用代碼編輯器修改此方法的內容。
        /// </summary>
        private void InitializeComponent()
        {
            this.btn_StopSocket = new System.Windows.Forms.Button();
            this.txt_Monitor = new System.Windows.Forms.TextBox();
            this.label3 = new System.Windows.Forms.Label();
            this.btn_StartSocket = new System.Windows.Forms.Button();
            this.txt_port = new System.Windows.Forms.TextBox();
            this.label2 = new System.Windows.Forms.Label();
            this.txt_ip = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.pictureBox1 = new System.Windows.Forms.PictureBox();
            this.btn_SendImg = new System.Windows.Forms.Button();
            this.btn_SendShake = new System.Windows.Forms.Button();
            this.btn_SendMes = new System.Windows.Forms.Button();
            this.label4 = new System.Windows.Forms.Label();
            this.txt_mes = new System.Windows.Forms.TextBox();
            this.listBox1 = new System.Windows.Forms.ListBox();
            this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
            this.lab_ImgName = new System.Windows.Forms.Label();
            this.groupBox1.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
            this.SuspendLayout();
            // 
            // btn_StopSocket
            // 
            this.btn_StopSocket.Location = new System.Drawing.Point(635, 10);
            this.btn_StopSocket.Name = "btn_StopSocket";
            this.btn_StopSocket.Size = new System.Drawing.Size(75, 23);
            this.btn_StopSocket.TabIndex = 15;
            this.btn_StopSocket.Text = "取消連接";
            this.btn_StopSocket.UseVisualStyleBackColor = true;
            this.btn_StopSocket.Click += new System.EventHandler(this.btn_StopSocket_Click);
            // 
            // txt_Monitor
            // 
            this.txt_Monitor.Location = new System.Drawing.Point(457, 14);
            this.txt_Monitor.Name = "txt_Monitor";
            this.txt_Monitor.ReadOnly = true;
            this.txt_Monitor.Size = new System.Drawing.Size(144, 21);
            this.txt_Monitor.TabIndex = 14;
            // 
            // label3
            // 
            this.label3.AutoSize = true;
            this.label3.Location = new System.Drawing.Point(398, 17);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(53, 12);
            this.label3.TabIndex = 13;
            this.label3.Text = "正在連接";
            // 
            // btn_StartSocket
            // 
            this.btn_StartSocket.Location = new System.Drawing.Point(307, 12);
            this.btn_StartSocket.Name = "btn_StartSocket";
            this.btn_StartSocket.Size = new System.Drawing.Size(75, 23);
            this.btn_StartSocket.TabIndex = 12;
            this.btn_StartSocket.Text = "開始連接";
            this.btn_StartSocket.UseVisualStyleBackColor = true;
            this.btn_StartSocket.Click += new System.EventHandler(this.btn_StartSocket_Click);
            // 
            // txt_port
            // 
            this.txt_port.Location = new System.Drawing.Point(183, 14);
            this.txt_port.Name = "txt_port";
            this.txt_port.Size = new System.Drawing.Size(100, 21);
            this.txt_port.TabIndex = 11;
            this.txt_port.Text = "9999";
            // 
            // label2
            // 
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(148, 19);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(29, 12);
            this.label2.TabIndex = 10;
            this.label2.Text = "端口";
            // 
            // txt_ip
            // 
            this.txt_ip.Location = new System.Drawing.Point(36, 14);
            this.txt_ip.Name = "txt_ip";
            this.txt_ip.Size = new System.Drawing.Size(100, 21);
            this.txt_ip.TabIndex = 9;
            this.txt_ip.Text = "127.0.0.1";
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(13, 17);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(17, 12);
            this.label1.TabIndex = 8;
            this.label1.Text = "IP";
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.Add(this.lab_ImgName);
            this.groupBox1.Controls.Add(this.pictureBox1);
            this.groupBox1.Controls.Add(this.btn_SendImg);
            this.groupBox1.Controls.Add(this.btn_SendShake);
            this.groupBox1.Controls.Add(this.btn_SendMes);
            this.groupBox1.Controls.Add(this.label4);
            this.groupBox1.Controls.Add(this.txt_mes);
            this.groupBox1.Controls.Add(this.listBox1);
            this.groupBox1.Location = new System.Drawing.Point(15, 48);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(939, 324);
            this.groupBox1.TabIndex = 16;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "發送與接收";
            // 
            // pictureBox1
            // 
            this.pictureBox1.Location = new System.Drawing.Point(346, 21);
            this.pictureBox1.Name = "pictureBox1";
            this.pictureBox1.Size = new System.Drawing.Size(281, 280);
            this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
            this.pictureBox1.TabIndex = 20;
            this.pictureBox1.TabStop = false;
            // 
            // btn_SendImg
            // 
            this.btn_SendImg.Location = new System.Drawing.Point(795, 267);
            this.btn_SendImg.Name = "btn_SendImg";
            this.btn_SendImg.Size = new System.Drawing.Size(75, 23);
            this.btn_SendImg.TabIndex = 19;
            this.btn_SendImg.Text = "發送圖片";
            this.btn_SendImg.UseVisualStyleBackColor = true;
            this.btn_SendImg.Click += new System.EventHandler(this.btn_SendImg_Click);
            // 
            // btn_SendShake
            // 
            this.btn_SendShake.Location = new System.Drawing.Point(714, 267);
            this.btn_SendShake.Name = "btn_SendShake";
            this.btn_SendShake.Size = new System.Drawing.Size(75, 23);
            this.btn_SendShake.TabIndex = 18;
            this.btn_SendShake.Text = "發送震動";
            this.btn_SendShake.UseVisualStyleBackColor = true;
            this.btn_SendShake.Click += new System.EventHandler(this.btn_SendShake_Click);
            // 
            // btn_SendMes
            // 
            this.btn_SendMes.Location = new System.Drawing.Point(633, 267);
            this.btn_SendMes.Name = "btn_SendMes";
            this.btn_SendMes.Size = new System.Drawing.Size(75, 23);
            this.btn_SendMes.TabIndex = 17;
            this.btn_SendMes.Text = "消息發送";
            this.btn_SendMes.UseVisualStyleBackColor = true;
            this.btn_SendMes.Click += new System.EventHandler(this.btn_SendMes_Click);
            // 
            // label4
            // 
            this.label4.AutoSize = true;
            this.label4.Location = new System.Drawing.Point(633, 6);
            this.label4.Name = "label4";
            this.label4.Size = new System.Drawing.Size(53, 12);
            this.label4.TabIndex = 17;
            this.label4.Text = "消息輸入";
            // 
            // txt_mes
            // 
            this.txt_mes.Location = new System.Drawing.Point(633, 21);
            this.txt_mes.Multiline = true;
            this.txt_mes.Name = "txt_mes";
            this.txt_mes.Size = new System.Drawing.Size(298, 240);
            this.txt_mes.TabIndex = 1;
            // 
            // listBox1
            // 
            this.listBox1.FormattingEnabled = true;
            this.listBox1.ItemHeight = 12;
            this.listBox1.Location = new System.Drawing.Point(7, 21);
            this.listBox1.Name = "listBox1";
            this.listBox1.Size = new System.Drawing.Size(332, 280);
            this.listBox1.TabIndex = 0;
            // 
            // openFileDialog1
            // 
            this.openFileDialog1.FileName = "openFileDialog1";
            // 
            // lab_ImgName
            // 
            this.lab_ImgName.AutoSize = true;
            this.lab_ImgName.Location = new System.Drawing.Point(351, 307);
            this.lab_ImgName.Name = "lab_ImgName";
            this.lab_ImgName.Size = new System.Drawing.Size(0, 12);
            this.lab_ImgName.TabIndex = 21;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(961, 386);
            this.Controls.Add(this.groupBox1);
            this.Controls.Add(this.btn_StopSocket);
            this.Controls.Add(this.txt_Monitor);
            this.Controls.Add(this.label3);
            this.Controls.Add(this.btn_StartSocket);
            this.Controls.Add(this.txt_port);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.txt_ip);
            this.Controls.Add(this.label1);
            this.Name = "Form1";
            this.Text = "客戶端";
            this.groupBox1.ResumeLayout(false);
            this.groupBox1.PerformLayout();
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button btn_StopSocket;
        private System.Windows.Forms.TextBox txt_Monitor;
        private System.Windows.Forms.Label label3;
        private System.Windows.Forms.Button btn_StartSocket;
        private System.Windows.Forms.TextBox txt_port;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.TextBox txt_ip;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.Button btn_SendShake;
        private System.Windows.Forms.Button btn_SendMes;
        private System.Windows.Forms.Label label4;
        private System.Windows.Forms.TextBox txt_mes;
        private System.Windows.Forms.ListBox listBox1;
        private System.Windows.Forms.Button btn_SendImg;
        private System.Windows.Forms.OpenFileDialog openFileDialog1;
        private System.Windows.Forms.PictureBox pictureBox1;
        private System.Windows.Forms.Label lab_ImgName;
    }
}
View Code

運行代碼:

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

namespace SocketClient
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        #region 參數聲明
        /// <summary>
        /// 根據IP:Port 存儲值
        /// </summary>
        static Dictionary<string, ServiceState> dic_ip = new Dictionary<string, ServiceState>();
        /// <summary>
        /// 客戶端socket
        /// </summary>
        Socket c_socket;

        Thread th_socket;

        int ConnectionResult = -2;
        #endregion

        /// <summary>
        /// 開啟Scoket連接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_StartSocket_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(this.txt_ip.Text.Trim()) && string.IsNullOrWhiteSpace(this.txt_port.Text.Trim()) && !string.IsNullOrWhiteSpace(this.txt_Monitor.Text.Trim()))
            {
                MessageBox.Show("輸入不符合或已經連接");
                return;
            }
            try
            {
                this.txt_ip.Enabled = false;
                this.txt_port.Enabled = false;
                Start();
                th_socket = new Thread(MonitorSocker);
                th_socket.IsBackground = true;
                th_socket.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + " " + ex.StackTrace);
                this.txt_ip.Enabled = true;
                this.txt_port.Enabled = true;
            }
        }

        //監聽Socket
        void MonitorSocker()
        {
            while (true)
            {
                if (ConnectionResult != 0 && ConnectionResult != -2)//通過錯誤碼判斷
                {
                    Start();
                    this.BeginInvoke((MethodInvoker)delegate ()
                    {
                        this.label3.Text = "重連中..";
                        this.txt_Monitor.Text = "errorCode" + ConnectionResult.ToString();
                    });
                    dic_ip = new Dictionary<string, ServiceState>();
                }
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// 關閉Socket連接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_StopSocket_Click(object sender, EventArgs e)
        {
            Stop();
        }

        /// <summary>
        /// 發送文本消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_SendMes_Click(object sender, EventArgs e)
        {
            try
            {
                SendSocket send = new SocketClient.SendSocket()
                {
                    Message = this.txt_mes.Text.Trim(),
                };
                Send(dic_ip[this.txt_Monitor.Text.Trim()].serviceSocket, send.ToArray());
                this.txt_mes.Text = "";
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + " " + ex.StackTrace);
            }
        }

        /// <summary>
        /// 發送震動
        /// </summary>
        private void btn_SendShake_Click(object sender, EventArgs e)
        {
            SendSocket send = new SocketClient.SendSocket()
            {
                SendShake = true,
                Message = "震動",
            };
            Send(dic_ip[this.txt_Monitor.Text.Trim()].serviceSocket, send.ToArray());
        }

        /// <summary>
        /// 發送圖片數據
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_SendImg_Click(object sender, EventArgs e)
        {
            //初始化一個OpenFileDialog類
            OpenFileDialog fileDialog = new OpenFileDialog();

            //判斷用戶是否正確的選擇了文件
            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                string extension = Path.GetExtension(fileDialog.FileName);
                string[] str = new string[] { ".gif", ".jpge", ".jpg", "bmp" };//准許上傳格式
                if (!((IList)str).Contains(extension))
                {
                    MessageBox.Show("僅能上傳gif,jpge,jpg,bmp格式的圖片!");
                }
                FileInfo fileInfo = new FileInfo(fileDialog.FileName);
                if (fileInfo.Length > 26214400)//不能大於25 
                {
                    MessageBox.Show("圖片不能大於25M");
                }

                //將圖片轉成base64發送
                SendSocket send = new SendSocket()
                {
                    SendImg = true,
                    ImgName = fileDialog.SafeFileName,
                };
                using (FileStream file = new FileStream(fileDialog.FileName, FileMode.Open, FileAccess.Read))
                {
                    var imgby = new byte[file.Length];
                    file.Read(imgby, 0, imgby.Length);
                    send.ImgBase64 = Convert.ToBase64String(imgby);
                }

                Send(dic_ip[this.txt_Monitor.Text.Trim()].serviceSocket, send.ToArray());
            }
        }

        /// <summary>
        /// 關閉socket
        /// </summary>
        public void Stop()
        {
            var key = this.txt_Monitor.Text.Trim();
            if (dic_ip.ContainsKey(key))
            {
                dic_ip.Remove(key);
            }
            if (c_socket == null)
                return;

            if (!c_socket.Connected)
                return;
            try
            {
                c_socket.Close();
            }
            catch
            {
            }
            this.txt_ip.Enabled = true;
            this.txt_port.Enabled = true;
            this.txt_Monitor.Text = null;
        }

        /// <summary>
        /// 連接Socket
        /// </summary>
        public void Start()
        {
            try
            {
                string ip = this.txt_ip.Text.Trim();
                int port = int.Parse(this.txt_port.Text.Trim());
                var endPoint = new IPEndPoint(IPAddress.Parse(ip), port);
                c_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                c_socket.BeginConnect(endPoint, new AsyncCallback(Connect), c_socket);
            }
            catch (SocketException ex)
            {
                Console.WriteLine("error ex=" + ex.Message + " " + ex.StackTrace);
                this.txt_ip.Enabled = true;
                this.txt_port.Enabled = true;
            }
        }

        #region Socket 連接 發送 接收
        /// <summary>
        /// 連接服務端
        /// </summary>
        /// <param name="ar"></param>
        private void Connect(IAsyncResult ar)
        {
            try
            {
                ServiceState obj = new ServiceState();
                Socket client = ar.AsyncState as Socket;
                obj.serviceSocket = client;

                //獲取服務端信息
                client.EndConnect(ar);

                //添加到字典集合
                dic_ip.Add(client.RemoteEndPoint.ToString(), obj);
                //顯示到txt文本
                this.BeginInvoke((MethodInvoker)delegate ()
                {
                    this.txt_Monitor.Text = client.RemoteEndPoint.ToString();
                });

                //接收連接Socket數據 
                client.BeginReceive(obj.buffer, 0, ServiceState.bufsize, SocketFlags.None, new AsyncCallback(ReadCallback), obj);

                ConnectionResult = 0;
            }
            catch (SocketException ex)
            {
                ConnectionResult = ex.ErrorCode;
                Console.WriteLine(ex.Message + " " + ex.StackTrace);
            }
        }

        /// <summary>
        /// 數據接收
        /// </summary>
        /// <param name="ar"></param>
        private void ReadCallback(IAsyncResult ar)
        {
            ServiceState obj = ar.AsyncState as ServiceState;
            Socket s_socket = obj.serviceSocket;
            try
            {
                if (s_socket.Connected)
                {
                    #region 接收數據處理
                    int bytes = s_socket.EndReceive(ar);
                    if (bytes == 16)
                    {
                        byte[] buf = obj.buffer;
                        //判斷頭部是否正確
                        if (buf[0] == 8 && buf[1] == 8 && buf[2] == 8 && buf[3] == 8)
                        {
                            //判斷是否為震動 標識12-15 1111
                            if (buf[12] == 1 && buf[13] == 1 && buf[14] == 1 && buf[15] == 1)
                            {
                                //實現震動效果
                                this.BeginInvoke((MethodInvoker)delegate ()
                                {
                                    int x = 5, y = 10;
                                    for (int i = 0; i < 5; i++)
                                    {
                                        this.Left += x;
                                        Thread.Sleep(y);
                                        this.Top += x;
                                        Thread.Sleep(y);
                                        this.Left -= x;
                                        Thread.Sleep(y);
                                        this.Top -= x;
                                        Thread.Sleep(y);
                                    }
                                });
                            }
                            else
                            {
                                int totalLength = BitConverter.ToInt32(buf, 4);
                                //獲取內容長度
                                int contentLength = BitConverter.ToInt32(buf, 8);
                                obj.buffer = new byte[contentLength];
                                int readDataPtr = 0;
                                while (readDataPtr < contentLength)
                                {
                                    var re = c_socket.Receive(obj.buffer, readDataPtr, contentLength - readDataPtr, SocketFlags.None);//接收內容
                                    readDataPtr += re;
                                }
                                //轉換顯示
                                var str = Encoding.UTF8.GetString(obj.buffer, 0, contentLength); //轉換顯示 UTF8

                                if (buf[12] == 2 && buf[13] == 2 && buf[14] == 2 && buf[15] == 2)
                                {
                                    #region 解析報文
                                    //解析XML 獲取圖片名稱和BASE64字符串
                                    XmlDocument document = new XmlDocument();
                                    document.LoadXml(str);
                                    XmlNodeList root = document.SelectNodes("/ImgMessage");
                                    string imgNmae = string.Empty, imgBase64 = string.Empty;
                                    foreach (XmlElement node in root)
                                    {
                                        imgNmae = node.GetElementsByTagName("ImgName")[0].InnerText;
                                        imgBase64 = node.GetElementsByTagName("ImgBase64")[0].InnerText;
                                    }

                                    //BASE64轉成圖片
                                    byte[] imgbuf = Convert.FromBase64String(imgBase64);
                                    using (System.IO.MemoryStream m_Str = new System.IO.MemoryStream(imgbuf))
                                    {
                                        using (Bitmap bit = new Bitmap(m_Str))
                                        {
                                            //保存到本地並上屏
                                            var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, imgNmae);
                                            bit.Save(path);
                                            pictureBox1.BeginInvoke((MethodInvoker)delegate ()
                                            {
                                                lab_ImgName.Text = imgNmae;
                                                pictureBox1.ImageLocation = path;
                                            });
                                        }
                                    }
                                    #endregion
                                }
                                else
                                {

                                    this.BeginInvoke((MethodInvoker)delegate ()
                                    {
                                        this.listBox1.Items.Add(DateTime.Now.ToString() + ":" + " 數據總長度 " + totalLength + " 內容長度 " + contentLength);
                                        this.listBox1.Items.Add(s_socket.RemoteEndPoint.ToString() + " " + str);
                                    });
                                }
                            }
                        }
                        obj.buffer = new byte[ServiceState.bufsize];
                        s_socket.BeginReceive(obj.buffer, 0, ServiceState.bufsize, 0, new AsyncCallback(ReadCallback), obj);
                    }
                    #endregion
                }
            }
            catch (SocketException ex)
            {
                ConnectionResult = ex.ErrorCode;
                Console.WriteLine(ex.Message + " " + ex.StackTrace);
            }
        }

        /// <summary>
        /// 發送
        /// </summary>
        /// <param name="s_socket"></param>
        /// <param name="mes"></param>
        private void Send(Socket s_socket, byte[] by)
        {
            try
            {
                //發送
                s_socket.BeginSend(by, 0, by.Length, SocketFlags.None, asyncResult =>
                {
                    try
                    {
                        //完成消息發送
                        int len = s_socket.EndSend(asyncResult);
                    }
                    catch (SocketException ex)
                    {
                        ConnectionResult = ex.ErrorCode;
                        Console.WriteLine(ex.Message + " " + ex.StackTrace);
                    }
                }, null);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + " " + ex.StackTrace);
            }
        }
        #endregion
    }
}
View Code

聲明的類:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace SocketClient
{

    /// <summary>
    /// 接收消息
    /// </summary>
    public class ServiceState
    {
        public Socket serviceSocket = null;
        public const int bufsize = 16;
        public byte[] buffer = new byte[bufsize];
        public StringBuilder str = new StringBuilder();
    }

    /// <summary>
    /// 0-3 標識碼 4-7 總長度 8-11 內容長度 12-15 補0/震動補1 16開始為內容
    /// </summary>
    public class SendSocket
    {
        /// <summary>
        /// 頭 標識8888
        /// </summary>
        byte[] Header = new byte[4] { 0x08, 0x08, 0x08, 0x08 };

        /// <summary>
        /// 文本消息
        /// </summary>
        public string Message;

        /// <summary>
        /// 是否發送震動
        /// </summary>
        public bool SendShake = false;

        /// <summary>
        /// 是否發送圖片
        /// </summary>
        public bool SendImg = false;

        /// <summary>
        /// 圖片名稱
        /// </summary>
        public string ImgName;

        /// <summary>
        /// 圖片數據
        /// </summary>
        public string ImgBase64;

        /// <summary>
        /// 組成特定格式的byte數據
        /// 12-15 為指定發送內容 1111(震動) 2222(圖片數據)
        /// </summary>
        /// <param name="mes">文本消息</param>
        /// <param name="Shake">震動</param>
        /// <param name="Img">圖片</param>
        /// <returns>特定格式的byte</returns>
        public byte[] ToArray()
        {
            if (SendImg)//是否發送圖片
            {
                //組成XML接收 可以接收相關圖片數據
                StringBuilder xmlResult = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
                xmlResult.Append("<ImgMessage>");
                xmlResult.AppendFormat("<ImgName>{0}</ImgName>", ImgName);
                xmlResult.AppendFormat("<ImgBase64>{0}</ImgBase64>", ImgBase64);
                xmlResult.Append("</ImgMessage>");
                Message = xmlResult.ToString();
            }

            byte[] byteData = Encoding.UTF8.GetBytes(Message);//內容
            int count = 16 + byteData.Length;//總長度
            byte[] SendBy = new byte[count];
            Array.Copy(Header, 0, SendBy, 0, Header.Length);//添加頭

            byte[] CountBy = BitConverter.GetBytes(count);
            Array.Copy(CountBy, 0, SendBy, 4, CountBy.Length);//總長度

            byte[] ContentBy = BitConverter.GetBytes(byteData.Length);
            Array.Copy(ContentBy, 0, SendBy, 8, ContentBy.Length);//內容長度

            if (SendShake)//發動震動
            {
                var shakeBy = new byte[4] { 1, 1, 1, 1 };
                Array.Copy(shakeBy, 0, SendBy, 12, shakeBy.Length);//震動
            }

            if (SendImg)//發送圖片
            {
                var imgBy = new byte[4] { 2, 2, 2, 2 };
                Array.Copy(imgBy, 0, SendBy, 12, imgBy.Length);//圖片
            }

            Array.Copy(byteData, 0, SendBy, 16, byteData.Length);//內容
            return SendBy;
        }
    }
}
View Code

 

百度雲盤下載地址:

鏈接:https://pan.baidu.com/s/1l8N1IQJn7Os15PIuSs6YjA
提取碼:dprj

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM