查看: 3917|回复: 12

[C/C++] 小练习:Tcp通信+线程间异步调用(In C#)

[复制链接]
发表于 2010-12-21 13:10 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?我要加入

x
本帖最后由 Rainyboy 于 2010-12-21 13:27 编辑

关于网络编程,现代的编程语言都会涉及,这里给出的是一个小练习,可以实现局域网聊天。


关于异步调用,一个形象的例子在帖子VC中如何实现一个窗口显示几秒后自动关闭?中就被提出过了。Windows下运行的程序都不停地等待用户的指令(即消息),然后在自身的消息-响应映射表中循环,找到合适的处理函数来对这个消息作出响应。因此,如刷新界面,接受用户的键盘输入,显示菜单等等都需要由程序的主线程来完成。这就导致了windows程序的主线程不适宜被长时间的阻塞,在某些时候,这又是不可避免的,例如本例中的TcpListener,就需要建立新的线程来单独负责此事,然而新的线程在执行时有需要对界面进行操作,在本例中,是实时地显示接受到的消息。为了满足这一系列需求,在这个小练习中采用了.NET平台中提供的代理(delegate)技术,代理即C/C++中函数指针的拓展,参考资料多如牛毛,具体用法无须赘述,上例子吧。

1.jpg









流程图为:

Tcp通信及线程间异步调用.jpg


代码:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Text;
  7. using System.Windows.Forms;
  8. using System.Threading;
  9. using System.Net;
  10. using System.Net.Sockets;


  11. namespace WindowsApplication1
  12. {
  13.     public partial class Form1 : Form
  14.     {
  15.         /// <summary>
  16.         /// 结束线程的标记
  17.         /// </summary>
  18.         public bool IsGoOn = true;

  19.         /// <summary>
  20.         /// 构造代理
  21.         /// </summary>
  22.         public delegate void Show_Rec_Delegate(String Msg);
  23.         public delegate void Show_Stp_Delegate(int Ds);
  24.         public delegate void Show_Sys_Delegate(String Msg);

  25.         /// <summary>
  26.         /// 通信层变量
  27.         /// </summary>
  28.         TcpListener server = null;

  29.         public Form1()
  30.         {
  31.             InitializeComponent();
  32.         }

  33.         /// <summary>
  34.         /// 开始发送内容
  35.         /// </summary>
  36.         /// <param name="sender"></param>
  37.         /// <param name="e"></param>
  38.         private void buttonOK_Click(object sender, EventArgs e)
  39.         {
  40.             try
  41.             {
  42.                 TcpClient client = new TcpClient(Str_TargetIP.Text, Convert.ToInt16(Str_SendPort.Text));
  43.                 String message = UserName.Text +": " +MsgSend.Text;
  44.                 Byte[] data = System.Text.Encoding.Unicode.GetBytes(message);
  45.                 NetworkStream stream = client.GetStream();
  46.                 stream.Write(data, 0, data.Length);
  47.                 WriteSysMsg("Sent: " + message);
  48.                 WriteRecMsg(message);
  49.                 stream.Close();
  50.                 client.Close();
  51.                 MsgSend.Text = String.Empty;
  52.                 toolStripProgressBar1.Value += 1;
  53.             }
  54.             catch (ArgumentNullException ex)
  55.             {
  56.                 WriteSysMsg("ArgumentNullException: "+ ex.Message);
  57.             }
  58.             catch (SocketException ex)
  59.             {
  60.                 WriteSysMsg("SocketException: "+ ex.Message);
  61.             }
  62.         }

  63.         /// <summary>
  64.         /// 创建并启动监听线程
  65.         /// </summary>
  66.         /// <param name="sender"></param>
  67.         /// <param name="e"></param>
  68.         private void Form1_Load(object sender, EventArgs e)
  69.         {
  70.             System.Net.IPAddress addr;

  71.             // 获得本机局域网IP地址

  72.             addr = new System.Net.IPAddress(Dns.GetHostByName(Dns.GetHostName()).AddressList[0].Address);

  73.             LocalIP.Text = addr.ToString();
  74.         }

  75.         /// <summary>
  76.         /// 用以将Msg显示在接收区域
  77.         /// </summary>
  78.         /// <param name="Msg"></param>
  79.         public void WriteRecMsg(String Msg)
  80.         {
  81.             MsgRecieve.Text += System.DateTime.Now  + Environment.NewLine + "  " + Msg + Environment.NewLine;
  82.         }

  83.         /// <summary>
  84.         /// 用以将Msg显示在系统消息区域
  85.         /// </summary>
  86.         /// <param name="Msg"></param>
  87.         public void WriteSysMsg(String Msg)
  88.         {
  89.             MsgSys.Text = System.DateTime.Now + ":" + Environment.NewLine + "  " + Msg + Environment.NewLine + MsgSys.Text;
  90.         }

  91.         /// <summary>
  92.         /// 用以用进度条记录当前监听线程的进度
  93.         /// </summary>
  94.         public void WriteListenStep(int Ds)
  95.         {
  96.             toolStripProgressBar2.Value = (toolStripProgressBar1.Value + Ds) % 100;
  97.         }


  98.         /// <summary>
  99.         /// UDP监听线程的实际操作函数
  100.         /// </summary>
  101.         public void UDP_Listener()
  102.         {
  103.             try
  104.             {
  105.                 //实例化代理
  106.                 Show_Rec_Delegate Show_Rec = new Show_Rec_Delegate(this.WriteRecMsg);
  107.                 Show_Stp_Delegate Show_Stp = new Show_Stp_Delegate(this.WriteListenStep);
  108.                 Show_Sys_Delegate Show_Sys = new Show_Sys_Delegate(this.WriteSysMsg);

  109.                 this.Invoke(Show_Sys, new object[] { "Tcp Listener Thread Start!" });
  110.                 try
  111.                 {
  112.                     Int32 port = Convert.ToInt32(Str_LinstenPort.Text);
  113.                     IPAddress localAddr = IPAddress.Parse(LocalIP.Text);
  114.                     server = new TcpListener(localAddr, port);
  115.                     server.Start();
  116.                     Byte[] bytes = new Byte[256];
  117.                     String data = null;
  118.                     // 进入监听循环
  119.                     while (IsGoOn)
  120.                     {
  121.                         this.Invoke(Show_Sys, new object[] { "Waiting for a connection... " });
  122.                         TcpClient client = server.AcceptTcpClient();
  123.                         this.Invoke(Show_Sys, new object[] { "Connected!" });
  124.                         data = null;
  125.                         NetworkStream stream = client.GetStream();
  126.                         int i;
  127.                         while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
  128.                         {
  129.                             data = System.Text.Encoding.Unicode.GetString(bytes, 0, i);
  130.                             this.Invoke(Show_Sys, new object[] { "Received: " + data });
  131.                             this.Invoke(Show_Rec, new object[] { data });
  132.                         }
  133.                         client.Close();
  134.                         //记录进度
  135.                         this.Invoke(Show_Stp, new object[] { 1 });
  136.                         Thread.Sleep(100);
  137.                     }
  138.                 }
  139.                 catch (SocketException ex)
  140.                 {
  141.                     this.Invoke(Show_Sys, new object[] { "SocketException: " + ex.Message });
  142.                 }
  143.                 finally
  144.                 {
  145.                     //退出server
  146.                     server.Stop();
  147.                     this.Invoke(Show_Sys, new object[] { "Tcp Listener Thread End!" });
  148.                 }
  149.             }
  150.             catch
  151.             {
  152.                 ;
  153.             }
  154.         }

  155.         /// <summary>
  156.         /// 在关闭窗口时结束线程
  157.         /// </summary>
  158.         /// <param name="sender"></param>
  159.         /// <param name="e"></param>
  160.         private void Form1_FormClosing(object sender, FormClosingEventArgs e)
  161.         {
  162.             IsGoOn=false;
  163.             if(server!=null)
  164.             {
  165.                 server.Stop();
  166.             }
  167.         }

  168.         private void 开始监听ToolStripMenuItem_Click(object sender, EventArgs e)
  169.         {
  170.             Thread UDP_lis_th = new Thread(new ThreadStart(this.UDP_Listener));
  171.             UDP_lis_th.Start();
  172.             toolStripProgressBar1.Value = 10;
  173.             toolStripProgressBar2.Value = 10;
  174.             //锁定参数窗口
  175.             Str_LinstenPort.Enabled = false;
  176.             Str_SendPort.Enabled = false;
  177.             Str_TargetIP.Enabled = false;
  178.             UserName.Enabled = false;
  179.             LocalIP.Enabled = false;
  180.         }

  181.         private void 结束监听ToolStripMenuItem_Click(object sender, EventArgs e)
  182.         {
  183.             IsGoOn = false;
  184.             if (server != null)
  185.             {
  186.                 server.Stop();
  187.             }
  188.             WriteSysMsg("Tcp Listener Thread End!");
  189.             toolStripProgressBar1.Value = 10;
  190.             toolStripProgressBar2.Value = 10;
  191.             Str_LinstenPort.Enabled = true;
  192.             Str_SendPort.Enabled = true;
  193.             Str_TargetIP.Enabled = true;
  194.             UserName.Enabled = true;
  195.             LocalIP.Enabled = true;
  196.         }

  197.         private void buttonExit_Click(object sender, EventArgs e)
  198.         {
  199.             IsGoOn = false;
  200.             if (server != null)
  201.             {
  202.                 server.Stop();
  203.             }
  204.             Close();
  205.         }

  206.     }
  207. }
复制代码


如何使用:
finally-如果你想在不同的机器上真正聊个天.jpg

填好相应的内容后,请点击“开始监听


附件为编译后的程序,运行需安装.NET framwork。



TCP_By_Rainyboy.rar

7.66 KB, 下载次数: 19

程序

Tcp通信及线程间异步调用.rar

51.92 KB, 下载次数: 20

流程图

点评

赞成: 5.0
赞成: 5
  发表于 2014-3-26 16:55

评分

1

查看全部评分

回复
分享到:

使用道具 举报

发表于 2010-12-23 10:24 | 显示全部楼层
你太牛了,,我搞通信的都不会。。。。。。
发表于 2010-12-23 10:27 | 显示全部楼层
代码规范 示例很好
 楼主| 发表于 2010-12-23 10:57 | 显示全部楼层
回复 2 # fxuestc 的帖子

哪里,你会起来很容易的,正是你们搞通信的所作出的工作,我们才能这么轻松地,在不了解底层细节的情况下,编写应用层的软件。写这个程序的时候才强烈的感受到,什么叫“分层”,什么叫“协议”,以及这些东西为什么能给软件开发带来便利。看看你们搞通信的,做得多么好,教科书般的经典!
发表于 2010-12-23 18:51 | 显示全部楼层
回复 4 # Rainyboy 的帖子

你太让我汗颜了
发表于 2011-2-16 11:51 | 显示全部楼层
先下下来了。。。学习
发表于 2011-3-2 20:51 | 显示全部楼层
长见识啦,
发表于 2011-6-15 09:18 | 显示全部楼层
很好啊,很厉害啊
发表于 2012-3-15 22:55 | 显示全部楼层
先下了学习 谢谢楼主
发表于 2012-7-16 20:03 | 显示全部楼层
学习了,谢谢斑竹。。。
发表于 2016-7-11 00:23 | 显示全部楼层
真是好东东,对楼主的辛勤工作和无私奉献致以崇高的敬意。
发表于 2016-7-11 08:28 | 显示全部楼层
连流程都有  good
您需要登录后才可以回帖 登录 | 我要加入

本版积分规则

快速回复 返回顶部 返回列表