有段時(shí)間沒有更博了,剛好最近在做Socket通信的項(xiàng)目,原理大致內(nèi)容:【二維碼-(加logo)】-->提供主機(jī)地址和端口號(hào)信息(直接使用【ThoughtWorks.QRCode.dll】比較簡(jiǎn)單就不贅述了,核心方法直接貼出來)。然后使用手機(jī)APP掃描進(jìn)行連接服務(wù)器,然后通過TCP/IP協(xié)議進(jìn)行握手傳輸,接收到的圖片按照一定的規(guī)則進(jìn)行排列。實(shí)時(shí)使用心跳包進(jìn)行檢測(cè),服務(wù)器進(jìn)行實(shí)時(shí)響應(yīng)。
一、二維碼+logo核心方法:
引用的命名空間是:using ThoughtWorks.QRCode.Codec;隨便用一個(gè)控件(比如:Image就可以show出來?。?/span>
二維碼+logo
二、重點(diǎn)分析心跳包與握手協(xié)議:
本次采用的是Socket進(jìn)行異步傳輸,首先要定義服務(wù)器地址和端口號(hào)(區(qū)分網(wǎng)路上其他主機(jī)的唯一標(biāo)識(shí));開始之前先申明:本文采用的機(jī)制是一個(gè)客戶端只使用一個(gè)Socket,服務(wù)器通過端口進(jìn)行監(jiān)聽,并發(fā)響應(yīng)客戶端。
* 服務(wù)器
A、定義Socket 和 獲取 監(jiān)聽服務(wù)器本機(jī)地址 端口號(hào)
1 //監(jiān)聽初始化2 private Socket listener = null;//連接客戶端3 private Socket RemoteClient = null;//接收消息4 5 private int port = 8089;6 private IPEndPoint listenEP = null;
B、定義好之后開始初始化數(shù)據(jù) ,使用AcceptCallback 進(jìn)行消息回調(diào)并等待客戶端觸發(fā)接收數(shù)據(jù)
1 private void RunsSocketServer() 2 { 3 listener = new Socket( 4 AddressFamily.InterNetwork, 5 SocketType.Stream, 6 ProtocolType.Tcp); 7 listener.Bind(listenEP); 8 listener.Listen(10); 9 listener.BeginAccept(10 new AsyncCallback(AcceptCallback),11 null);12 13 LB_TXT.Content = "監(jiān)聽已開啟" + listener.LocalEndPoint.ToString() + "";14 15 }
C、回調(diào)函數(shù)
1 private void AcceptCallback(IAsyncResult iar) 2 { 3 try 4 { 5 RemoteClient = listener.EndAccept(iar); 6 //同進(jìn)程上的線程異步 7 this.Dispatcher.BeginInvoke((MethodInvoker)delegate () 8 { 9 LB_TXT.Content = string.Format("{0}已連接到服務(wù)器", RemoteClient.RemoteEndPoint.ToString());10 });11 12 ReceivePicHandShakes();//握手協(xié)議及接收?qǐng)D片13 14 }15 catch (Exception err)16 {17 this.Dispatcher.BeginInvoke((MethodInvoker)delegate ()18 {19 LB_TXT.Content = err.Message;20 });21 return;22 }23 }
D、通過開辟一個(gè)新的線程進(jìn)行異步接收數(shù)據(jù)(圖中的協(xié)議使用XXX代替,請(qǐng)大家根據(jù)自己的協(xié)議需要進(jìn)行定義)
1 Thread _timers = null; 2 private Socket _SocketClient = null; 3 byte[] RecvBytes = new byte[50]; 4 private int Numimgs = 0;//記錄接收成功的張數(shù) 5 //byte[] ReImgBytes = new byte[8];//接收?qǐng)D片的頭字節(jié) 6 public event ReceivedBitmapHandler ReceivedBitmap; 7 private delegate void RestartThread();//定義委托 8 9 10 public TransferHandler(Socket client) 11 { 12 _SocketClient = client; 13 } 14 15 #region 服務(wù)器端 16 public void BeginReceive() 17 { 18 //采用線程直接接收的方式 19 _timers = new Thread(StartToReceive); 20 _timers.IsBackground = true; 21 _timers.Start(); 22 } 23 /// <summary> 24 /// 開始接收消息 25 /// </summary> 26 private void StartToReceive() 27 { 28 //由于long占8位字節(jié),所以先獲取前8位字節(jié)數(shù)據(jù) 29 IAsyncResult iar = _SocketClient.BeginReceive( 30 RecvBytes, 31 0, 32 RecvBytes.Length, 33 SocketFlags.None, 34 null, 35 null); 36 int len = _SocketClient.EndReceive(iar); 37 string ReceivemMsg = Encoding.ASCII.GetString(RecvBytes, 0, len); 38 if (ReceivemMsg.IndexOf("xxx") > 0)//區(qū)分業(yè)務(wù)消息和心跳檢測(cè)消息 39 { 40 _SocketClient.Send(Encoding.ASCII.GetBytes("xxx"));//回應(yīng)心跳包 41 RecvBytes = new byte[RecvBytes.Length]; //清空數(shù)據(jù) 42 StartToReceive();//回應(yīng)心跳包完成之后繼續(xù)等待接收 43 } 44 else if (ReceivemMsg == "xxx")//如果收到這個(gè)請(qǐng)求,告訴客戶端可以開始發(fā)送第一張圖片了 45 { 46 string order = "xxx"; 47 byte[] orderdata = Encoding.ASCII.GetBytes(order); //把字符串編碼為字節(jié) 48 _SocketClient.Send(orderdata); 49 RecvBytes = new byte[8]; //開始接收?qǐng)D片 50 StartToReceive();//回應(yīng)指令后完成之后繼續(xù)等待接收 51 } 52 else if (ReceivemMsg == "xxx") 53 { 54 //停止接收?qǐng)D片 55 string order = "xxxx";//通知客戶端已經(jīng)完成接收這次所有圖片,結(jié)束傳輸; 56 byte[] orderdata = Encoding.ASCII.GetBytes(order); //把字符串編碼為字節(jié) 57 _SocketClient.Send(orderdata); 58 StartToReceive(); 59 } 60 else 61 { 62 int offset = 0; 63 int length = BitConverter.ToInt32(RecvBytes, offset); //先獲取文件長(zhǎng)度 64 ReceiveFile(length); 65 } 66 67 } 68 69 70 public void ReceiveFile(long filelen) 71 { 72 MemoryStream ms = new MemoryStream(); 73 int bytesRead = 0; 74 long count = 0; 75 byte[] buffer = new byte[8192]; 76 77 while (count != filelen) 78 { 79 try 80 { 81 bytesRead = _SocketClient.Receive(buffer); 82 ms.Write(buffer, 0, bytesRead); 83 count += bytesRead; 84 } 85 catch (Exception ex) 86 { 87 88 } 89 } 90 ReceivedBitmap(new Bitmap(ms)); 91 92 93 //接收完成之后清空數(shù)據(jù),繼續(xù)接收 94 buffer = new byte[buffer.Length];//緩存 95 RecvBytes = new byte[RecvBytes.Length];//用于接收 96 97 string order = "xxxx";//通知客戶端已經(jīng)收到圖片,請(qǐng)繼續(xù) 98 byte[] orderdata = Encoding.ASCII.GetBytes(order); //把字符串編碼為字節(jié) 99 _SocketClient.Send(orderdata);100 Numimgs++;101 102 if (Numimgs >= 3)103 {104 RecvBytes = new byte[50];105 Numimgs = 0;106 }107 StartToReceive(); //接收完成之后繼續(xù)接收108 }109 #endregion
* 客戶端
A、心跳包發(fā)送(代碼中XXX解釋同上)
1 #region 心跳檢測(cè) 2 private void HeartBeatsTests() 3 { 4 Thread sendEcho = new Thread(new ThreadStart(socketSend)); 5 sendEcho.Start(); 6 sendEcho.IsBackground = true; 7 } 8 9 10 public void socketSend()11 {12 while (true)13 {14 Thread.Sleep(10000);//每十秒發(fā)一次,響應(yīng)發(fā)3次15 //備注:IsSendingImgs必須放在sleep底下,防止等待的空余時(shí)間發(fā)送導(dǎo)致服務(wù)端繼續(xù)接收心跳包16 if (!IsSendingImgs)//如果是任務(wù)還在執(zhí)行不允許第二次發(fā)送,必須要等待完成17 {18 try19 {20 this.Dispatcher.BeginInvoke((MethodInvoker)delegate ()21 {22 this.richTextBox.AppendText("開始發(fā)送心跳包..." + Environment.NewLine);23 });24 client.Send(Encoding.ASCII.GetBytes("xxxx"));//發(fā)送心跳暗號(hào)25 }26 catch (SocketException)27 {28 Thread.CurrentThread.Abort();29 //throw ex;30 }31 //標(biāo)記發(fā)送的次數(shù)32 this.MyLostTime++;33 //如果外發(fā)了3次請(qǐng)求暗號(hào)后仍不見服務(wù)器的回應(yīng),則認(rèn)為客戶端已經(jīng)與服務(wù)器斷開聯(lián)系了34 if (this.MyLostTime >= 3)35 {36 //IsSendingImgs = true;37 TimeSpan t = DateTime.Now - lastConnect;38 if (t.TotalSeconds > 30)39 {40 this.Dispatcher.BeginInvoke((MethodInvoker)delegate ()41 {42 //this.richTextBox.cont43 this.richTextBox.AppendText("與服務(wù)器失去聯(lián)系..." + Environment.NewLine);44 });45 }46 else47 {48 49 this.countnum++;50 this.Dispatcher.BeginInvoke((MethodInvoker)delegate ()51 {52 //this.richTextBox.cont53 this.richTextBox.AppendText("服務(wù)器響應(yīng)第" + countnum.ToString() + "次,響應(yīng)時(shí)間是:" + DateTime.Now.ToString() + ";" + Environment.NewLine);54 });55 }56 //每次確定后重置57 this.MyLostTime = 0;58 }59 }60 else61 {62 lastConnect = DateTime.Now;//每十秒刷新,防止圖片傳送任務(wù)完成之后導(dǎo)致時(shí)間錯(cuò)誤;63 }64 }65 66 }67 68 #endregion
B、響應(yīng)機(jī)制(發(fā)送圖片及接收消息觸發(fā)停止、開啟心跳包代碼中XXX解釋同上)
1 /// <summary> 2 /// 協(xié)議請(qǐng)求 3 /// </summary> 4 public void SendSocketData() 5 { 6 string sendStr = "xxx"; //向服務(wù)器發(fā)送請(qǐng)求:發(fā)送3張圖片的指令 7 byte[] buffer = Encoding.ASCII.GetBytes(sendStr); //把字符串編碼為字節(jié) 8 _SendQuest.Send(buffer); //發(fā)送 9 _SendQuest.BeginReceive(Rbuffer, 0, Rbuffer.Length, 0, new AsyncCallback(CallbackRuquest), null);//等待接收并回調(diào)10 }11 12 13 /// <summary>14 /// 回調(diào)告訴socket可以執(zhí)行下一步了15 /// </summary>16 /// <param name="iar"></par
此文的Demo下載地址:Socket心跳通信
http://www.cnblogs.com/BarryJames/p/7161791.html