Real time Application 實時申請技術在本文裡是作為一個實例來演示在用戶(Tcpclient)申請與服務器(TcpServer)申請之間使用Socket類的情況 。該項目同樣也演示在實時項目中如何使用listview控制以及如何傳遞XML格式信息。
TcpServer.exe 文件顯示了在單獨的thread當中(而不是在GUI 線程之中)TCP socket的相互通訊。
TcpClient.exe文件同樣也使用一條單獨的線程 從Socket中讀取數據,然後對表單中的list view控件進行更新。
步聚如下:
1.TcpServer 監聽端口8002,並且發射線程等待客戶端連結。
Hashtable socketHolder = new Hashtable(); Hashtable threadHolder = new Hashtable(); public Form1() { // Required for Windows Form Designer support // InitializeComponent(); tcpLsn = new TcpListener(8002); tcpLsn.Start(); // tcpLsn.LocalEndpoint may have a bug, it only show 0.0.0.0:8002 stpanel.Text = "Listen at: " + tcpLsn.LocalEndpoint.ToString(); Thread tcpThd = new Thread(new ThreadStart(WaitingForClient)); threadHolder.Add(connectId, tcpThd); tcpThd.Start() ; }2. TcpClient與TcpSrv連接上後,發送客戶端信息數據包至TcpServer,然後發射線程,該線程是用來接收通過Socket傳來的數據。
private void menuConn_Click(object sender, System.EventArgs e) { ConnectDlg myDlg = new ConnectDlg(); myDlg.ShowDialog(this); if( myDlg.DialogResult==DialogResult.OK) { s = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp ); IPAddress hostadd = IPAddress.Parse(myDlg.IpAdd); int port=Int32.Parse(myDlg.PortNum); IPEndPoint EPhost = new IPEndPoint(hostadd, port); Try { s.Connect(EPhost); if (s.Connected) { Byte[] bBuf; string buf; buf = String.Format("{0}:{1}", myDlg.UserName,myDlg.PassWord); bBuf=ASCII.GetBytes(buf); s.Send(bBuf, 0 , bBuf.Length,0); t = new Thread(new ThreadStart(StartRecieve)); t.Start(); sbar.Text="Ready to recieve data"; } } catch (Exception e1) { MessageBox.Show(e1.ToString()); } } } private void StartRecieve() { miv = new MethodInvoker(this.UpdateListView); int cnt=0; string tmp=null; Byte[] firstb= new Byte[1]; while (true) { try { Byte[] receive = new Byte[1]; int ret = s.Receive(receive, 1, 0); if (ret > 0) { switch(receive[0]) { case 11: //check start message cnt=0; break; case 10: // check end message cnt=0; if(firstb[0] == ':') HandleCommand(tmp); else if(firstb[0] == '<') HandleXml(tmp); else HandleText(tmp); tmp=null; break; default: if (cnt == 0) firstb[0] = receive[0]; tmp += System.Text.Encoding .ASCII.GetString(receive); cnt++; break; } } } catch (Exception e) { if( !s.Connected ) { break; } } } t.Abort(); }3.TcpServer接收來自TcpClient的連接請求,並且將socket 實例保存到Hash表中,然後發射線程以便控制socket的通訊,同時將客戶端信息在listview 控件中顯示出來。
public void WaitingForClient() { while(true) { // Accept will block until someone connects Socket sckt = tcpLsn.AcceptSocket(); if (connectId < 10000) Interlocked.Increment(ref connectId); Else connectId = 1; if (socketHolder.Count < MaxConnected ) { while (socketHolder.Contains(connectId) ) { Interlocked.Increment(ref connectId); } Thread td = new Thread(new ThreadStart(ReadSocket)); lock(this) { // it is used to keep connected Sockets socketHolder.Add(connectId, sckt); // it is used to keep the active thread threadHolder.Add(connectId, td); } td.Start(); } } } // follow function handle the communication from the clients and close the // socket and the thread when the socket connection is down public void ReadSocket() { // the connectId is keeping changed with new connection added. it can't // be used to keep the real connectId, the local variable realId will // keep the value when the thread started. long realId = connectId; int ind=-1; Socket s = (Socket)socketHolder[realId]; while (true) { if(s.Connected) { Byte[] receive = new Byte[37] ; Try { // Receive will block until data coming // ret is 0 or Exception happen when Socket connection // is broken int ret=s.Receive(receive,receive.Length,0); if (ret > 0) { string tmp = null; tmp=System.Text.Encoding.ASCII.GetString(receive); if(tmp.Length > 0) { DateTime now1=DateTime.Now; String strDate; strDate = now1.ToShortDateString() + " " + now1.ToLongTimeString(); ListViewItem newItem = new ListViewItem(); string[] strArry=tmp.Split(':'); int code = checkUserInfo(strArry[0]); if(code==2) { userHolder.Add(realId, strArry[0]); newItem.SubItems.Add(strArry[0]); newItem.ImageIndex = 0; newItem.SubItems.Add(strDate); this.listView2.Items.Add(newItem); ind=this.listView2.Items.IndexOf(newItem); } else if( code==1) } } else { this.listView2.Items[ind].ImageIndex=1; keepUser=false; break; } } catch (Exception e) { if( !s.Connected ) { this.listView2.Items[ind].ImageIndex=1; keepUser=false; break; } } } } CloseTheThread(realId); } private void CloseTheThread(long realId) { socketHolder.Remove(realId); if(!keepUser) userHolder.Remove(realId); lock(this) { Thread thd = (Thread)threadHolder[realId]; threadHolder.Remove(realId); } thd.Abort(); }4. 點擊Load Data菜單,從文件中載入信息,然後把所有信息傳送到每個將與TcpServer相連接的客戶端,客戶端會自己更新它的listview。不管是TcpServer 還是 TcpClient ,它們都從運作中的線程之中獲取數據,再在主線程中更新Listview control。下面則講述的是通過MethodInvoker實現該功能。