前言
看了一百遍,不如動手寫一遍。
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; } }
運行代碼:

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; } } }
聲明的類:

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; } } }
客戶端
窗體(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; } }
運行代碼:

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 } }
聲明的類:

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; } } }
百度雲盤下載地址:
鏈接:https://pan.baidu.com/s/1l8N1IQJn7Os15PIuSs6YjA
提取碼:dprj