• 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

  • 相关阅读:
    sql server 2008 评估期已过期解决办法 + vs2008破解(转) 狼人:
    发现godaddy亚太机房主机比较慢,怎样转到godaddy美国机房 狼人:
    模拟提交有文件上传的表单(通过http模拟上传文件) 狼人:
    WordPress 批量关闭和打开评论功能 狼人:
    英文seo外链资源整合,怎么样找国外博客资源? 狼人:
    WindowsServer2003+IIS6+ASP+NET+PHP+MSSQL+MYSQL配置说明 |备份于waw.cnblogs.com 狼人:
    Excel表格的35招必学秘技(学会计的快来转载,留着以后用) 狼人:
    MSN去窗口广告方法http://apatch.org/downloads/ 狼人:
    js 实现谷歌浏览器中隐藏标签后setInterval事件暂停 狼人:
    SQL Server 2008过期导致MSSQLSERVER服务无法启动 狼人:
  • 原文地址:https://www.cnblogs.com/psjinfo/p/10485224.html
Copyright © 2020-2023  润新知