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實現該功能。