VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > C#教程 >
  • c#实时申请技术

制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
 

  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实现该功能。

 

  public void LoadThread()
{
MethodInvoker mi = new MethodInvoker(this.UpdateListView);
string tmp = null;
StreamReader sr = File.OpenText("Issue.txt");
while((tmp = sr.ReadLine()) !=null )
{
if (tmp =="")
break;
isu.symbol= Mid(tmp, 0, 4);
isu.bid = Mid(tmp, 4, 5);
isu.offer = Mid(tmp, 9, 5);
isu.volume = Mid(tmp, 16, tmp.Length-16);
sendMsg ="\v" + tmp + "\n"; //add send message's head and end char
SendDataToAllClient(tmp);
this.BeginInvoke(mi);
JobDone.WaitOne();
}
sr.Close();
fThd.Abort();
}
private void SendDataToAllClient(string str)
{
foreach (Socket s in socketHolder.Values)
{
if(s.Connected)
{
Byte[] byteDateLine=ASCII.GetBytes(str.ToCharArray());
s.Send(byteDateLine, byteDateLine.Length, 0);
}
}
}

  以下代码 操纵XML文件,并且为客户端生成XML文件。

  public void LoadXmlThread()
{
MethodInvoker miv = new MethodInvoker(this.UpdateListView);
string tmp = null;
string xmlString = null;
int recordFlg = -1;
int textCount =0;
xmlString = "\v"+"";
XmlTextReader tr = new XmlTextReader("issue.xml");
while(tr.Read())
{
switch (tr.NodeType)
{
case XmlNodeType.Element:
if (tr.Name == "Issue")
{
recordFlg++;
if(recordFlg > 0)
{
textCount=0;
xmlString += CreateXmlElement(
tr.Name, 2);
xmlString += "\n";
SendDataToAllClient(xmlString);
xmlString = "\v"+"
version='1.0'?>";
this.BeginInvoke(miv);
JobDone.WaitOne();
}
}
if (recordFlg >= 0)
{
xmlString += CreateXmlElement(
tr.Name, 1);
tmp = tr.Name;
}
break;
case XmlNodeType.Text:
switch(++textCount)
{
case 1:
isu.symbol=tr.Value;
break;
case 2:
isu.bid=tr.Value;
break;
case 3:
isu.offer=tr.Value;
break;
case 4:
isu.volume=tr.Value;
break;
}
xmlString += tr.Value;
xmlString += CreateXmlElement(tmp, 2);
break;
}
}
fThd.Abort();
}
string CreateXmlElement(string elem, int ord)
{
string tmp = null;
if (ord == 1)
tmp = String.Format("<{0}>", elem);
else
tmp = String.Format("", elem);
return tmp;
}
以下功能演示的是如何设置TcpClient中Listview控件的 BackColor和 Forecolor属性 。
private void UpdateListView()
{
int ind=-1;
for (int i=0; i < this.listView1.Items.Count;i++)
{
if (this.listView1.Items[i].Text == isu.symbol.ToString())
{
ind=i;
break;
}
}
if (ind == -1)
{
ListViewItem newItem new ListViewItem(isu.symbol.ToString());
newItem.SubItems.Add(isu.bid);
newItem.SubItems.Add(isu.offer);
newItem.SubItems.Add(isu.volume);
this.listView1.Items.Add(newItem);
int i=this.listView1.Items.IndexOf(newItem);
setRowColor(i, System.Drawing.Color.FromArgb(255, 255, 175));
setColColorHL(i, 0, System.Drawing.Color.FromArgb(128,0,0));
setColColorHL(i, 1, System.Drawing.Color.FromArgb(128,0,0));
this.listView1.Update();
Thread.Sleep(300);
setColColor(i, 0, System.Drawing.Color.FromArgb(255, 255,175));
setColColor(i, 1, System.Drawing.Color.FromArgb(255, 255, 175));
}
else
{
this.listView1.Items[ind].Text = isu.symbol.ToString();
this.listView1.Items[ind].SubItems[1].Text = (isu.bid);
this.listView1.Items[ind].SubItems[2].Text = (isu.offer);
this.listView1.Items[ind].SubItems[3].Text = (isu.volume);
setColColorHL(ind, 0, System.Drawing.Color.FromArgb(128,0,0));
setColColorHL(ind, 1, System.Drawing.Color.FromArgb(128,0,0));
this.listView1.Update();
Thread.Sleep(300);
setColColor(ind, 0, System.Drawing.Color.FromArgb(255,255,175));
setColColor(ind, 1, System.Drawing.Color.FromArgb(255,255,175));
}
JobDone.Set();
}
private void setRowColor(int rowNum, Color colr )
{
for (int i=0; i < this.listView1.Items[rowNum].SubItems.Count;i++)
if (rowNum%2 !=0)
this.listView1.Items[rowNum].SubItems[i].BackColor = colr;
}
private void setColColor(int rowNum, int colNum, Color colr )
{
if (rowNum%2 !=0)
this.listView1.Items[rowNum].SubItems[colNum].BackColor=colr;
else
this.listView1.Items[rowNum].SubItems[colNum].BackColor =
System.Drawing.Color.FromArgb(248, 248,248);
if (colNum==0)
{
this.listView1.Items[rowNum].SubItems[colNum].ForeColor =
System.Drawing.Color.FromArgb(128, 0, 64);
this.listView1.Items[rowNum].SubItems[colNum].BackColor =
System.Drawing.Color.FromArgb(197, 197, 182);
}
else
this.listView1.Items[rowNum].SubItems[colNum].ForeColor =
System.Drawing.Color.FromArgb(20, 20,20);
}
private void setColColorHL(int rowNum, int colNum, Color colr )
{
this.listView1.Items[rowNum].SubItems[colNum].BackColor = colr;
this.listView1.Items[rowNum].SubItems[colNum].ForeColor =
System.Drawing.Color.FromArgb(255,255,255);
}

 

  运行该例子的步骤

  1. 在A机上运行TcpServer.exe文件。

  2. 在A机或B机上运行一次或多次TcpClient.exe文件。

  3. 在TcpClient端,点击菜单连接,进入TcpServer正在运行中的服务器端。在编辑栏键入用户名及口令,点击确认。

  4. 当在TcpServer顶部的istview上瞧见客户端的提示时,则在TcpServer,上点击Load Data菜单,然后实时数据则会出现在TcpServer 和TcpClien上。

  注意:请确认Data file, Issue.txt and Issue.xml等文件总是处于同一根目录下,正如TcpSvr.exe 和 MaskedTextBox.dll, WTcpClient.exe.是处于同一目录下一样。

  Update at 10/20/2001.

  当添加/删除项目时,请锁住Hash表,这样可以确保线程的安全。

  添加功能,以便生成和处理XML格式文件。

  在发送讯息至客户端时,请在服务器端添加发送讯息起始和结尾的字符。

  上述方法可以增加客户端的稳定性。

 

 

  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实现该功能。



相关教程