小练习:Tcp通信+线程间异步调用(In C#)
本帖最后由 Rainyboy 于 2010-12-21 13:27 编辑关于网络编程,现代的编程语言都会涉及,这里给出的是一个小练习,可以实现局域网聊天。
关于异步调用,一个形象的例子在帖子VC中如何实现一个窗口显示几秒后自动关闭?中就被提出过了。Windows下运行的程序都不停地等待用户的指令(即消息),然后在自身的消息-响应映射表中循环,找到合适的处理函数来对这个消息作出响应。因此,如刷新界面,接受用户的键盘输入,显示菜单等等都需要由程序的主线程来完成。这就导致了windows程序的主线程不适宜被长时间的阻塞,在某些时候,这又是不可避免的,例如本例中的TcpListener,就需要建立新的线程来单独负责此事,然而新的线程在执行时有需要对界面进行操作,在本例中,是实时地显示接受到的消息。为了满足这一系列需求,在这个小练习中采用了.NET平台中提供的代理(delegate)技术,代理即C/C++中函数指针的拓展,参考资料多如牛毛,具体用法无须赘述,上例子吧。
流程图为:
代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net;
using System.Net.Sockets;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
/// <summary>
/// 结束线程的标记
/// </summary>
public bool IsGoOn = true;
/// <summary>
/// 构造代理
/// </summary>
public delegate void Show_Rec_Delegate(String Msg);
public delegate void Show_Stp_Delegate(int Ds);
public delegate void Show_Sys_Delegate(String Msg);
/// <summary>
/// 通信层变量
/// </summary>
TcpListener server = null;
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 开始发送内容
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonOK_Click(object sender, EventArgs e)
{
try
{
TcpClient client = new TcpClient(Str_TargetIP.Text, Convert.ToInt16(Str_SendPort.Text));
String message = UserName.Text +": " +MsgSend.Text;
Byte[] data = System.Text.Encoding.Unicode.GetBytes(message);
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
WriteSysMsg("Sent: " + message);
WriteRecMsg(message);
stream.Close();
client.Close();
MsgSend.Text = String.Empty;
toolStripProgressBar1.Value += 1;
}
catch (ArgumentNullException ex)
{
WriteSysMsg("ArgumentNullException: "+ ex.Message);
}
catch (SocketException ex)
{
WriteSysMsg("SocketException: "+ ex.Message);
}
}
/// <summary>
/// 创建并启动监听线程
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
System.Net.IPAddress addr;
// 获得本机局域网IP地址
addr = new System.Net.IPAddress(Dns.GetHostByName(Dns.GetHostName()).AddressList.Address);
LocalIP.Text = addr.ToString();
}
/// <summary>
/// 用以将Msg显示在接收区域
/// </summary>
/// <param name="Msg"></param>
public void WriteRecMsg(String Msg)
{
MsgRecieve.Text += System.DateTime.Now+ Environment.NewLine + "" + Msg + Environment.NewLine;
}
/// <summary>
/// 用以将Msg显示在系统消息区域
/// </summary>
/// <param name="Msg"></param>
public void WriteSysMsg(String Msg)
{
MsgSys.Text = System.DateTime.Now + ":" + Environment.NewLine + "" + Msg + Environment.NewLine + MsgSys.Text;
}
/// <summary>
/// 用以用进度条记录当前监听线程的进度
/// </summary>
public void WriteListenStep(int Ds)
{
toolStripProgressBar2.Value = (toolStripProgressBar1.Value + Ds) % 100;
}
/// <summary>
/// UDP监听线程的实际操作函数
/// </summary>
public void UDP_Listener()
{
try
{
//实例化代理
Show_Rec_Delegate Show_Rec = new Show_Rec_Delegate(this.WriteRecMsg);
Show_Stp_Delegate Show_Stp = new Show_Stp_Delegate(this.WriteListenStep);
Show_Sys_Delegate Show_Sys = new Show_Sys_Delegate(this.WriteSysMsg);
this.Invoke(Show_Sys, new object[] { "Tcp Listener Thread Start!" });
try
{
Int32 port = Convert.ToInt32(Str_LinstenPort.Text);
IPAddress localAddr = IPAddress.Parse(LocalIP.Text);
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte;
String data = null;
// 进入监听循环
while (IsGoOn)
{
this.Invoke(Show_Sys, new object[] { "Waiting for a connection... " });
TcpClient client = server.AcceptTcpClient();
this.Invoke(Show_Sys, new object[] { "Connected!" });
data = null;
NetworkStream stream = client.GetStream();
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.Unicode.GetString(bytes, 0, i);
this.Invoke(Show_Sys, new object[] { "Received: " + data });
this.Invoke(Show_Rec, new object[] { data });
}
client.Close();
//记录进度
this.Invoke(Show_Stp, new object[] { 1 });
Thread.Sleep(100);
}
}
catch (SocketException ex)
{
this.Invoke(Show_Sys, new object[] { "SocketException: " + ex.Message });
}
finally
{
//退出server
server.Stop();
this.Invoke(Show_Sys, new object[] { "Tcp Listener Thread End!" });
}
}
catch
{
;
}
}
/// <summary>
/// 在关闭窗口时结束线程
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
IsGoOn=false;
if(server!=null)
{
server.Stop();
}
}
private void 开始监听ToolStripMenuItem_Click(object sender, EventArgs e)
{
Thread UDP_lis_th = new Thread(new ThreadStart(this.UDP_Listener));
UDP_lis_th.Start();
toolStripProgressBar1.Value = 10;
toolStripProgressBar2.Value = 10;
//锁定参数窗口
Str_LinstenPort.Enabled = false;
Str_SendPort.Enabled = false;
Str_TargetIP.Enabled = false;
UserName.Enabled = false;
LocalIP.Enabled = false;
}
private void 结束监听ToolStripMenuItem_Click(object sender, EventArgs e)
{
IsGoOn = false;
if (server != null)
{
server.Stop();
}
WriteSysMsg("Tcp Listener Thread End!");
toolStripProgressBar1.Value = 10;
toolStripProgressBar2.Value = 10;
Str_LinstenPort.Enabled = true;
Str_SendPort.Enabled = true;
Str_TargetIP.Enabled = true;
UserName.Enabled = true;
LocalIP.Enabled = true;
}
private void buttonExit_Click(object sender, EventArgs e)
{
IsGoOn = false;
if (server != null)
{
server.Stop();
}
Close();
}
}
}
如何使用:
填好相应的内容后,请点击“开始监听”
附件为编译后的程序,运行需安装.NET framwork。
你太牛了,,我搞通信的都不会。。。。。。{:{28}:}{:{28}:} 代码规范 示例很好 回复 2 # fxuestc 的帖子
哪里,你会起来很容易的,正是你们搞通信的所作出的工作,我们才能这么轻松地,在不了解底层细节的情况下,编写应用层的软件。写这个程序的时候才强烈的感受到,什么叫“分层”,什么叫“协议”,以及这些东西为什么能给软件开发带来便利。看看你们搞通信的,做得多么好,教科书般的经典! 回复 4 # Rainyboy 的帖子
你太让我汗颜了{:{28}:}{:{28}:}{:{28}:} 先下下来了。。。学习{:{23}:} 长见识啦,{:{23}:} 很好啊,很厉害啊 先下了学习 谢谢楼主{:{39}:} {:{39}:}学习了,谢谢斑竹。。。 真是好东东,对楼主的辛勤工作和无私奉献致以崇高的敬意。 连流程都有good
页:
[1]