VS2010 C# 你得学会并且学得会的Socket编程基础知识(Silverlight Socket编程)
来源:互联网 发布:淘宝app怎么换皮肤 编辑:程序博客网 时间:2024/05/17 23:34
这一篇文章,我将图文并茂地介绍Socket编程的基础知识,我相信,如果你按照步骤做完实验,一定可以对Socket编程有更好地理解。
本文源代码,可以通过这里下载 http://files.cnblogs.com/chenxizhang/SocketWorkshop.rar
第一步:创建解决方案
第二步:创建服务端程序
这里可以选择“Console Application”这个类型,比较方便调试
然后编写如下代码,实现服务器的基本功能
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="rem" style="color: rgb(0, 128, 0); ">//额外导入的两个命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketServer{ <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> Program { <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Socket Server 演示</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Main(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>[] args) { <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个新的Socket,这里我们使用最常用的基于TCP的Stream Socket(流式套接字)</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//将该socket绑定到主机上面的某个端口</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.bind.aspx</span> socket.Bind(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> IPEndPoint(IPAddress.Any, 4530)); <span class="rem" style="color: rgb(0, 128, 0); ">//启动监听,并且设置一个最大的队列长度</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.listen(v=VS.100).aspx</span> socket.Listen(4); Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"Server is ready!"</span>); Console.Read(); } }}
现在可以启动调试一下看看效果如何,正常情况下应该会看到一个提示,因为我们需要在TCP 4530端口进行监听,所以防火墙会有提示。
点击“Allow access”
这样,我们的服务器就可以开始监听了。但是这有什么用呢?是的,没有什么用。
我们还需要为服务器添加一些功能,例如接受传入的请求,给客户端发送消息,或者从客户端接收消息等等
第三步:接受传入的请求
我们需要通过Accept,或者(BeginAccept)来接受传入的请求,请注意下面代码中的红色部分
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="rem" style="color: rgb(0, 128, 0); ">//额外导入的两个命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketServer{ <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> Program { <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Socket Server 演示</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Main(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>[] args) { <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个新的Socket,这里我们使用最常用的基于TCP的Stream Socket(流式套接字)</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//将该socket绑定到主机上面的某个端口</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.bind.aspx</span> socket.Bind(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> IPEndPoint(IPAddress.Any, 4530)); <span class="rem" style="color: rgb(0, 128, 0); ">//启动监听,并且设置一个最大的队列长度</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.listen(v=VS.100).aspx</span> socket.Listen(4);<strong><span style="color: rgb(255, 0, 0); "> <span class="rem" style="color: rgb(0, 128, 0); ">//开始接受客户端连接请求</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.beginaccept.aspx</span> socket.BeginAccept(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback((ar) => { <span class="rem" style="color: rgb(0, 128, 0); ">//这就是客户端的Socket实例,我们后续可以将其保存起来</span> var client = socket.EndAccept(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//给客户端发送一个欢迎消息</span> client.Send(Encoding.Unicode.GetBytes(<span class="str" style="color: rgb(0, 96, 128); ">"Hi there, I accept you request at "</span>+DateTime.Now.ToString())); }), <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>);</span></strong> Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"Server is ready!"</span>); Console.Read(); } }}
wow,看起来不错对吧,我们赶紧做一个客户端来测试一下吧
第四步:创建客户端
我们还是使用一个Console Application
添加如下的代码,并且创建客户端连接
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="rem" style="color: rgb(0, 128, 0); ">//导入的命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketClient{ <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> Program { <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Socket Server 演示</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Main(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>[] args) { <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个Socket</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//连接到指定服务器的指定端口</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.connect.aspx</span> socket.Connect(<span class="str" style="color: rgb(0, 96, 128); ">"localhost"</span>, 4530); Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"connect to the server"</span>); Console.Read(); } }}
依次选择SocketServer和SocketClient这两个项目,分别将其启动为调试状态(右键菜单,Debug=>Start new instance)
我们看到两个程序都工作正常。
但是,在客户端怎么没有收到服务器发过来的消息呢?那是因为,我们没有在客户端提供这方面的功能。
第五步:在客户端中实现接受消息的方法
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="rem" style="color: rgb(0, 128, 0); ">//导入的命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketClient{ <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> Program { <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Socket Server 演示</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Main(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>[] args) { <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个Socket</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//连接到指定服务器的指定端口</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.connect.aspx</span> socket.Connect(<span class="str" style="color: rgb(0, 96, 128); ">"localhost"</span>, 4530); <span class="rem" style="color: rgb(0, 128, 0); ">//实现接受消息的方法</span><strong><span style="color: rgb(255, 0, 0); "> var buffer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[1024];<span class="rem" style="color: rgb(0, 128, 0); ">//设置一个缓冲区,用来保存数据</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.beginreceive.aspx</span> socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback((ar) => { <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.endreceive.aspx</span> var length = socket.EndReceive(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//读取出来消息内容</span> var message = Encoding.Unicode.GetString(buffer, 0, length); <span class="rem" style="color: rgb(0, 128, 0); ">//显示消息</span> Console.WriteLine(message); }), <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>);</span></strong> Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"connect to the server"</span>); Console.Read(); } }}
请注意以上红色的部分,我们用了BeginReceive方法进行异步的消息侦听,如果收到了,我们就打印出来
看起来已经实现了我们需求了:服务器给客户端发了一个消息,而客户端也已经收到了。
但是,这远远不够,因为它们之间的通讯不仅仅是一次性的,那么如果服务器要不断地给客户端发消息,例如每隔两秒钟就发送一个消息,如何实现呢?
第六步:实现服务器定期向客户端发消息
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="rem" style="color: rgb(0, 128, 0); ">//额外导入的两个命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketServer{ <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> Program { <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Socket Server 演示</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Main(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>[] args) { <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个新的Socket,这里我们使用最常用的基于TCP的Stream Socket(流式套接字)</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//将该socket绑定到主机上面的某个端口</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.bind.aspx</span> socket.Bind(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> IPEndPoint(IPAddress.Any, 4530)); <span class="rem" style="color: rgb(0, 128, 0); ">//启动监听,并且设置一个最大的队列长度</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.listen(v=VS.100).aspx</span> socket.Listen(4); <span class="rem" style="color: rgb(0, 128, 0); ">//开始接受客户端连接请求</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.beginaccept.aspx</span> socket.BeginAccept(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback((ar) => { <span class="rem" style="color: rgb(0, 128, 0); ">//这就是客户端的Socket实例,我们后续可以将其保存起来</span> var client = socket.EndAccept(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//给客户端发送一个欢迎消息</span> client.Send(Encoding.Unicode.GetBytes(<span class="str" style="color: rgb(0, 96, 128); ">"Hi there, I accept you request at "</span>+DateTime.Now.ToString()));<strong><span style="color: rgb(255, 0, 0); "> <span class="rem" style="color: rgb(0, 128, 0); ">//实现每隔两秒钟给服务器发一个消息</span> <span class="rem" style="color: rgb(0, 128, 0); ">//这里我们使用了一个定时器</span> var timer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> System.Timers.Timer(); timer.Interval = 2000D; timer.Enabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">true</span>; timer.Elapsed += (o, a) => { client.Send(Encoding.Unicode.GetBytes(<span class="str" style="color: rgb(0, 96, 128); ">"Message from server at "</span> +DateTime.Now.ToString())); }; timer.Start();</span></strong> }), <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>); Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"Server is ready!"</span>); Console.Read(); } }}
我们还要实现在客户端一直监听消息的机制,而不是一次性接收.请注意下面红色的部分
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="rem" style="color: rgb(0, 128, 0); ">//导入的命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketClient{ <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> Program { <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Socket Server 演示</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Main(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>[] args) { <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个Socket</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//连接到指定服务器的指定端口</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.connect.aspx</span> socket.Connect(<span class="str" style="color: rgb(0, 96, 128); ">"localhost"</span>, 4530); Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"connect to the server"</span>); <span class="rem" style="color: rgb(0, 128, 0); ">//实现接受消息的方法</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.beginreceive.aspx</span> <strong><span style="color: rgb(255, 0, 0); "> socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ReceiveMessage),socket);</span></strong> Console.Read(); }<span style="color: rgb(255, 0, 0); "><strong> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[] buffer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[1024]; <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> ReceiveMessage(IAsyncResult ar) { <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { var socket = ar.AsyncState <span class="kwrd" style="color: rgb(0, 0, 255); ">as</span> Socket; <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.endreceive.aspx</span> var length = socket.EndReceive(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//读取出来消息内容</span> var message = Encoding.Unicode.GetString(buffer, 0, length); <span class="rem" style="color: rgb(0, 128, 0); ">//显示消息</span> Console.WriteLine(message); <span class="rem" style="color: rgb(0, 128, 0); ">//接收下一个消息(因为这是一个递归的调用,所以这样就可以一直接收消息了)</span> socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ReceiveMessage), socket); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(Exception ex){ Console.WriteLine(ex.Message); } }</strong></span> }}
重新调试起来,看起来的效果如下图所示
我们继续做下面的实验,一步一步地研究Socket通讯中可能遇到的一些问题
请先关闭掉客户端这个程序,而不要关闭服务端程序,这时会发现一个错误
这个错误很容易理解,因为客户端已经关闭,也就是客户端那个Socket已经不存在了,服务器还继续向它发送消息当然会出错。所以,从可靠性方面的考虑,我们必须在发送消息之前检测Socket的活动状态
第七步:检测客户端的活动状态
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="rem" style="color: rgb(0, 128, 0); ">//额外导入的两个命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketServer{ <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> Program { <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Socket Server 演示</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Main(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>[] args) { <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个新的Socket,这里我们使用最常用的基于TCP的Stream Socket(流式套接字)</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//将该socket绑定到主机上面的某个端口</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.bind.aspx</span> socket.Bind(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> IPEndPoint(IPAddress.Any, 4530)); <span class="rem" style="color: rgb(0, 128, 0); ">//启动监听,并且设置一个最大的队列长度</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.listen(v=VS.100).aspx</span> socket.Listen(4); <span class="rem" style="color: rgb(0, 128, 0); ">//开始接受客户端连接请求</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.beginaccept.aspx</span> socket.BeginAccept(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback((ar) => { <span class="rem" style="color: rgb(0, 128, 0); ">//这就是客户端的Socket实例,我们后续可以将其保存起来</span> var client = socket.EndAccept(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//给客户端发送一个欢迎消息</span> client.Send(Encoding.Unicode.GetBytes(<span class="str" style="color: rgb(0, 96, 128); ">"Hi there, I accept you request at "</span>+DateTime.Now.ToString())); <span class="rem" style="color: rgb(0, 128, 0); ">//实现每隔两秒钟给服务器发一个消息</span> <span class="rem" style="color: rgb(0, 128, 0); ">//这里我们使用了一个定时器</span> var timer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> System.Timers.Timer(); timer.Interval = 2000D; timer.Enabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">true</span>; timer.Elapsed += (o, a) => {<strong><span style="color: rgb(255, 0, 0); "> <span class="rem" style="color: rgb(0, 128, 0); ">//检测客户端Socket的状态</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">if</span>(client.Connected) { <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { client.Send(Encoding.Unicode.GetBytes(<span class="str" style="color: rgb(0, 96, 128); ">"Message from server at "</span> + DateTime.Now.ToString())); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(SocketException ex) { Console.WriteLine(ex.Message); } } <span class="kwrd" style="color: rgb(0, 0, 255); ">else</span> { timer.Stop(); timer.Enabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">false</span>; Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"Client is disconnected, the timer is stop."</span>); }</span></strong> }; timer.Start(); }), <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>); Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"Server is ready!"</span>); Console.Read(); } }}
上面代码的逻辑很清楚,但有时候还是会触发那个SocketException。为什么呢?这是因为我们的Timer是每隔两秒钟检查一次,那么就很可能有一种情况,我们检查的时候,它还是连接状态,消息发出去之后,它断开了。这种情况肯定是存在的。所以要用Try..catch的结构
目前我们实现的场景很简单,服务器只管发消息,客户端只管收消息。但实际工作中,可能希望服务器和客户端都能收发消息。请看下一节
第八步:实现双向收发消息
先看服务端的修改
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="rem" style="color: rgb(0, 128, 0); ">//额外导入的两个命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketServer{ <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> Program { <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Socket Server 演示</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Main(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>[] args) { <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个新的Socket,这里我们使用最常用的基于TCP的Stream Socket(流式套接字)</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//将该socket绑定到主机上面的某个端口</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.bind.aspx</span> socket.Bind(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> IPEndPoint(IPAddress.Any, 4530)); <span class="rem" style="color: rgb(0, 128, 0); ">//启动监听,并且设置一个最大的队列长度</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.listen(v=VS.100).aspx</span> socket.Listen(4); <span class="rem" style="color: rgb(0, 128, 0); ">//开始接受客户端连接请求</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.beginaccept.aspx</span> socket.BeginAccept(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback((ar) => { <span class="rem" style="color: rgb(0, 128, 0); ">//这就是客户端的Socket实例,我们后续可以将其保存起来</span> var client = socket.EndAccept(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//给客户端发送一个欢迎消息</span> client.Send(Encoding.Unicode.GetBytes(<span class="str" style="color: rgb(0, 96, 128); ">"Hi there, I accept you request at "</span>+DateTime.Now.ToString())); <span class="rem" style="color: rgb(0, 128, 0); ">//实现每隔两秒钟给服务器发一个消息</span> <span class="rem" style="color: rgb(0, 128, 0); ">//这里我们使用了一个定时器</span> var timer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> System.Timers.Timer(); timer.Interval = 2000D; timer.Enabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">true</span>; timer.Elapsed += (o, a) => { <span class="rem" style="color: rgb(0, 128, 0); ">//检测客户端Socket的状态</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">if</span>(client.Connected) { <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { client.Send(Encoding.Unicode.GetBytes(<span class="str" style="color: rgb(0, 96, 128); ">"Message from server at "</span> + DateTime.Now.ToString())); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(SocketException ex) { Console.WriteLine(ex.Message); } } <span class="kwrd" style="color: rgb(0, 0, 255); ">else</span> { timer.Stop(); timer.Enabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">false</span>; Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"Client is disconnected, the timer is stop."</span>); } }; timer.Start(); <strong><span style="color: rgb(255, 0, 0); "> <span class="rem" style="color: rgb(0, 128, 0); ">//接收客户端的消息(这个和在客户端实现的方式是一样的)</span> client.BeginReceive(buffer,0,buffer.Length,SocketFlags.None,<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ReceiveMessage),client);</span></strong> }), <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>); Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"Server is ready!"</span>); Console.Read(); }<strong><span style="color: rgb(255, 0, 0); "> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[] buffer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[1024]; <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> ReceiveMessage(IAsyncResult ar) { <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { var socket = ar.AsyncState <span class="kwrd" style="color: rgb(0, 0, 255); ">as</span> Socket; <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.endreceive.aspx</span> var length = socket.EndReceive(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//读取出来消息内容</span> var message = Encoding.Unicode.GetString(buffer, 0, length); <span class="rem" style="color: rgb(0, 128, 0); ">//显示消息</span> Console.WriteLine(message); <span class="rem" style="color: rgb(0, 128, 0); ">//接收下一个消息(因为这是一个递归的调用,所以这样就可以一直接收消息了)</span> socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ReceiveMessage), socket); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(Exception ex){ Console.WriteLine(ex.Message); } }</span></strong> }}
可以看出来,为了让服务器可以接受消息,其实并不需要什么特别的设计,与客户端接受消息其实可以是一样的
再来看看客户端的修改
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="rem" style="color: rgb(0, 128, 0); ">//导入的命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketClient{ <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> Program { <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Socket Server 演示</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Main(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>[] args) { <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个Socket</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//连接到指定服务器的指定端口</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.connect.aspx</span> socket.Connect(<span class="str" style="color: rgb(0, 96, 128); ">"localhost"</span>, 4530); Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"connect to the server"</span>); <span class="rem" style="color: rgb(0, 128, 0); ">//实现接受消息的方法</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.beginreceive.aspx</span> socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ReceiveMessage), socket);<strong><span style="color: rgb(255, 0, 0); "> <span class="rem" style="color: rgb(0, 128, 0); ">//接受用户输入,将消息发送给服务器端</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">while</span>(<span class="kwrd" style="color: rgb(0, 0, 255); ">true</span>) { var message = <span class="str" style="color: rgb(0, 96, 128); ">"Message from client : "</span> + Console.ReadLine(); var outputBuffer = Encoding.Unicode.GetBytes(message); socket.BeginSend(outputBuffer, 0, outputBuffer.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>, <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>); }</span></strong> } <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[] buffer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[1024]; <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> ReceiveMessage(IAsyncResult ar) { <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { var socket = ar.AsyncState <span class="kwrd" style="color: rgb(0, 0, 255); ">as</span> Socket; <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.endreceive.aspx</span> var length = socket.EndReceive(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//读取出来消息内容</span> var message = Encoding.Unicode.GetString(buffer, 0, length); <span class="rem" style="color: rgb(0, 128, 0); ">//显示消息</span> Console.WriteLine(message); <span class="rem" style="color: rgb(0, 128, 0); ">//接收下一个消息(因为这是一个递归的调用,所以这样就可以一直接收消息了)</span> socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ReceiveMessage), socket); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(Exception ex) { Console.WriteLine(ex.Message); } } }}
我在这里做了一个死循环,用户可以不断地输入,这些消息会被发送给服务器。如下图所示
【备注】因为服务器每隔两秒钟会发送新消息过来,所以在输入的时候,动作要稍快一点啦
本文最后探讨一个问题,就是如何让我们的服务器可以支持多个客户端
第九步:支持多个客户端
这个步骤只需要修改服务端程序即可
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="rem" style="color: rgb(0, 128, 0); ">//额外导入的两个命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketServer{ <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> Program { <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Socket Server 演示</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Main(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>[] args) { <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个新的Socket,这里我们使用最常用的基于TCP的Stream Socket(流式套接字)</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//将该socket绑定到主机上面的某个端口</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.bind.aspx</span> socket.Bind(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> IPEndPoint(IPAddress.Any, 4530)); <span class="rem" style="color: rgb(0, 128, 0); ">//启动监听,并且设置一个最大的队列长度</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.listen(v=VS.100).aspx</span> socket.Listen(4); <span class="rem" style="color: rgb(0, 128, 0); ">//开始接受客户端连接请求</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.beginaccept.aspx</span> <span style="color: rgb(255, 0, 0); "><strong> socket.BeginAccept(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ClientAccepted), socket);</strong></span> Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"Server is ready!"</span>); Console.Read(); }<strong><span style="color: rgb(255, 0, 0); "> <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> ClientAccepted(IAsyncResult ar) { var socket = ar.AsyncState <span class="kwrd" style="color: rgb(0, 0, 255); ">as</span> Socket; <span class="rem" style="color: rgb(0, 128, 0); ">//这就是客户端的Socket实例,我们后续可以将其保存起来</span> var client = socket.EndAccept(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//给客户端发送一个欢迎消息</span> client.Send(Encoding.Unicode.GetBytes(<span class="str" style="color: rgb(0, 96, 128); ">"Hi there, I accept you request at "</span> + DateTime.Now.ToString())); <span class="rem" style="color: rgb(0, 128, 0); ">//实现每隔两秒钟给服务器发一个消息</span> <span class="rem" style="color: rgb(0, 128, 0); ">//这里我们使用了一个定时器</span> var timer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> System.Timers.Timer(); timer.Interval = 2000D; timer.Enabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">true</span>; timer.Elapsed += (o, a) => { <span class="rem" style="color: rgb(0, 128, 0); ">//检测客户端Socket的状态</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">if</span>(client.Connected) { <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { client.Send(Encoding.Unicode.GetBytes(<span class="str" style="color: rgb(0, 96, 128); ">"Message from server at "</span> + DateTime.Now.ToString())); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(SocketException ex) { Console.WriteLine(ex.Message); } } <span class="kwrd" style="color: rgb(0, 0, 255); ">else</span> { timer.Stop(); timer.Enabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">false</span>; Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"Client is disconnected, the timer is stop."</span>); } }; timer.Start(); <span class="rem" style="color: rgb(0, 128, 0); ">//接收客户端的消息(这个和在客户端实现的方式是一样的)</span> client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ReceiveMessage), client); <span class="rem" style="color: rgb(0, 128, 0); ">//准备接受下一个客户端请求</span> socket.BeginAccept(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ClientAccepted), socket); }</span></strong> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[] buffer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[1024]; <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> ReceiveMessage(IAsyncResult ar) { <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { var socket = ar.AsyncState <span class="kwrd" style="color: rgb(0, 0, 255); ">as</span> Socket; <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.endreceive.aspx</span> var length = socket.EndReceive(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//读取出来消息内容</span> var message = Encoding.Unicode.GetString(buffer, 0, length); <span class="rem" style="color: rgb(0, 128, 0); ">//显示消息</span> Console.WriteLine(message); <span class="rem" style="color: rgb(0, 128, 0); ">//接收下一个消息(因为这是一个递归的调用,所以这样就可以一直接收消息了)</span> socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ReceiveMessage), socket); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(Exception ex){ Console.WriteLine(ex.Message); } } }}
最后调试起来看到的效果如下图
本文源代码,可以通过这里下载 http://files.cnblogs.com/chenxizhang/SocketWorkshop.rar
本文将在这个案例的基础上,加入一个特殊场景,利用Silverlight来实现客户端。有的朋友可能会说,其实是一样的吧。请不要急于下结论,有用过Silverlight的朋友都有这种体会,很多在标准.NET Framework编程中能用的技术,到了Silverlight里面,或多或少会有些限制。不幸的是,Socket这个功能就是其中一个。这本身没有什么好不好的问题,Silverlight首先是运行在一个特殊的沙盒中,受到一些限制也是意料之中的,毕竟安全第一嘛
我总结Silverlight中应用Socket的几点特殊之处
1.所有的操作都必须的异步的,包括连接,发送和接收消息
2.Silverlight只能做客户端,不能做服务器(虽然这句看起来说的有点多余,不过确实有朋友想这么做呢)
3.Silverlight的Socket只能访问如下端口,4502-4530,只能用TCP。
4.Silverlight的Socket收到访问策略的限制,服务端必须监听,并提供ClientAccessPolicy的支持。通常是在943端口(TCP)进行监听,也可以在HTTP 80端口监听。
本文完整代码如下 http://files.cnblogs.com/chenxizhang/SocketWorkshop(with-silverlight).rar
那么,我们就来通过例子学习一下在Silverlight中如何使用Socket技术与服务端通讯吧
第一步:创建Silverlight项目
第二步:设计Silverlight界面
<span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">UserControl</span> <span class="attr" style="color: rgb(255, 0, 0); ">x:Class</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="SocketSilverlightClient.MainPage"</span> <span class="attr" style="color: rgb(255, 0, 0); ">xmlns</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span> <span class="attr" style="color: rgb(255, 0, 0); ">xmlns:x</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="http://schemas.microsoft.com/winfx/2006/xaml"</span> <span class="attr" style="color: rgb(255, 0, 0); ">xmlns:d</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="http://schemas.microsoft.com/expression/blend/2008"</span> <span class="attr" style="color: rgb(255, 0, 0); ">xmlns:mc</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="http://schemas.openxmlformats.org/markup-compatibility/2006"</span> <span class="attr" style="color: rgb(255, 0, 0); ">mc:Ignorable</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="d"</span> <span class="attr" style="color: rgb(255, 0, 0); ">d:DesignHeight</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="300"</span> <span class="attr" style="color: rgb(255, 0, 0); ">d:DesignWidth</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="400"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Grid</span> <span class="attr" style="color: rgb(255, 0, 0); ">x:Name</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="LayoutRoot"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Background</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="White"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Margin</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="20"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Grid.Resources</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Style</span> <span class="attr" style="color: rgb(255, 0, 0); ">TargetType</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Button"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span> <span class="attr" style="color: rgb(255, 0, 0); ">Property</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Width"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Value</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="100"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span> <span class="attr" style="color: rgb(255, 0, 0); ">Property</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="HorizontalAlignment"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Value</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Left"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span> <span class="attr" style="color: rgb(255, 0, 0); ">Property</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Margin"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Value</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="5"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "></</span><span class="html" style="color: rgb(128, 0, 0); ">Style</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Style</span> <span class="attr" style="color: rgb(255, 0, 0); ">TargetType</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="TextBlock"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span> <span class="attr" style="color: rgb(255, 0, 0); ">Property</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Margin"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Value</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="5"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span> <span class="attr" style="color: rgb(255, 0, 0); ">Property</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="HorizontalAlignment"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Value</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Left"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span> <span class="attr" style="color: rgb(255, 0, 0); ">Property</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="TextWrapping"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Value</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Wrap"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></</span><span class="html" style="color: rgb(128, 0, 0); ">Setter</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "></</span><span class="html" style="color: rgb(128, 0, 0); ">Style</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "></</span><span class="html" style="color: rgb(128, 0, 0); ">Grid.Resources</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">StackPanel</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Button</span> <span class="attr" style="color: rgb(255, 0, 0); ">Content</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Connect"</span> <span class="attr" style="color: rgb(255, 0, 0); ">x:Name</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="btConnect"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Click</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="btConnect_Click"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></</span><span class="html" style="color: rgb(128, 0, 0); ">Button</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">TextBlock</span> <span class="attr" style="color: rgb(255, 0, 0); ">Text</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Type your message"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></</span><span class="html" style="color: rgb(128, 0, 0); ">TextBlock</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">StackPanel</span> <span class="attr" style="color: rgb(255, 0, 0); ">Margin</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="5"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Orientation</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Horizontal"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">TextBox</span> <span class="attr" style="color: rgb(255, 0, 0); ">x:Name</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="txtInput"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Width</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="200"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></</span><span class="html" style="color: rgb(128, 0, 0); ">TextBox</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">Button</span> <span class="attr" style="color: rgb(255, 0, 0); ">Content</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Send"</span> <span class="attr" style="color: rgb(255, 0, 0); ">x:Name</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="btSend"</span> <span class="attr" style="color: rgb(255, 0, 0); ">Click</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="btSend_Click"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></</span><span class="html" style="color: rgb(128, 0, 0); ">Button</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "></</span><span class="html" style="color: rgb(128, 0, 0); ">StackPanel</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">TextBlock</span> <span class="attr" style="color: rgb(255, 0, 0); ">Text</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="Messages from server"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></</span><span class="html" style="color: rgb(128, 0, 0); ">TextBlock</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "><</span><span class="html" style="color: rgb(128, 0, 0); ">ItemsControl</span> <span class="attr" style="color: rgb(255, 0, 0); ">Margin</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="5"</span> <span class="attr" style="color: rgb(255, 0, 0); ">x:Name</span><span class="kwrd" style="color: rgb(0, 0, 255); ">="icResult"</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "></</span><span class="html" style="color: rgb(128, 0, 0); ">ItemsControl</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "></</span><span class="html" style="color: rgb(128, 0, 0); ">StackPanel</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span> <span class="kwrd" style="color: rgb(0, 0, 255); "></</span><span class="html" style="color: rgb(128, 0, 0); ">Grid</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span><span class="kwrd" style="color: rgb(0, 0, 255); "></</span><span class="html" style="color: rgb(128, 0, 0); ">UserControl</span><span class="kwrd" style="color: rgb(0, 0, 255); ">></span>
这个界面看起来像下面这样
第三步:编写基本的客户端代码
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Controls;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Documents;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Input;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Media;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Media.Animation;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Shapes;<span class="rem" style="color: rgb(0, 128, 0); ">//导入命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketSilverlightClient{ <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 演示如何在Silverlight中使用Socket技术</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">partial</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> MainPage : UserControl { <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> MainPage() { InitializeComponent(); } <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 尝试连接到服务器</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="sender"></param></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="e"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">private</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> btConnect_Click(<span class="kwrd" style="color: rgb(0, 0, 255); ">object</span> sender, RoutedEventArgs e) { <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个套接字</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//准备一个异步参数(这是特有的)</span> var args = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> SocketAsyncEventArgs(); <span class="rem" style="color: rgb(0, 128, 0); ">//设置远程服务器地址,这里用DnsSafeHost,可以获取到宿主远程服务器的主机名称</span> args.RemoteEndPoint = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> DnsEndPoint(App.Current.Host.Source.DnsSafeHost, 4530); <span class="rem" style="color: rgb(0, 128, 0); ">//注册Completed事件处理程序</span> args.Completed += (o, a) => { <span class="kwrd" style="color: rgb(0, 0, 255); ">if</span>(a.SocketError > 0)<span class="rem" style="color: rgb(0, 128, 0); ">//0表示成功,其他的表示有错误</span> { <span class="rem" style="color: rgb(0, 128, 0); ">//注意,因为Completed方法是在工作线程触发的,所以要对主线程进行访问,必须使用Dispatcher机制</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">this</span>.Dispatcher.BeginInvoke(() => { MessageBox.Show(<span class="str" style="color: rgb(0, 96, 128); ">"Connect fail:"</span> + a.SocketError.ToString()); }); } <span class="kwrd" style="color: rgb(0, 0, 255); ">else</span> { <span class="kwrd" style="color: rgb(0, 0, 255); ">this</span>.Dispatcher.BeginInvoke(() => { MessageBox.Show(<span class="str" style="color: rgb(0, 96, 128); ">"Connect success"</span>); }); } }; <span class="rem" style="color: rgb(0, 128, 0); ">//发起异步的连接请求</span> socket.ConnectAsync(args); } <span class="kwrd" style="color: rgb(0, 0, 255); ">private</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> btSend_Click(<span class="kwrd" style="color: rgb(0, 0, 255); ">object</span> sender, RoutedEventArgs e) { } }}
【注意】在Silverlight中使用Socket的代码,与一般的客户端还是不同的。最主要的区别在于异步模型。
目前,我这里只编写了Connect的代码,是因为这里就会遇到连接问题,其他代码先不着急写出来。我们可以运行起来看看
点击“Connect”之后,我们发现有一个错误,是AccessDenied。这就是说,Silverlight遇到了权限问题无法直接访问到服务器。
我们都知道,Silverlight是运行在一个沙盒里面的,它要访问宿主网站之外的资源,是受到很多限制的。它会先尝试检查目标资源是否有一个ClientAccessPolicy的设置。
这里有一篇详细的介绍 http://msdn.microsoft.com/zh-cn/library/cc197955(VS.95).aspx
第四步:为服务器添加PolicyServer。
已经有不少先进同学在这方面有研究了。这个PolicyServer是负责向Silverlight发送策略信息的,也就是说,Silverlight的Socket,在连接之前,会默认去连接目标主机的943端口,请求ClientAccessPolicy的认证,只有通过了,则可以继续访问其他的Socket。
这个PolicyServer的设计,不是我的原创,但我稍做了修改。请将下面的代码保存为一个独立的文件,放在SocketServer这个项目里面
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Configuration;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Diagnostics;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.IO;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Reflection;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketServerService{ <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// This is a silverlight socket client access policy file server.</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Background:</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// When a socket connection open attempt to some server is made in Silverlight 2.0</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Silverlight automatically makes a request to the server in question on port 943 for a policy file</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// The policy file served includes the valid ports and valid clients for the socket server</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Outcomes:</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// The socket request will result in success if the client access policy file served by the socket</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// server permits access to the requested port and the client URI is in the <allow-from> element</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// See ClientAccessPolicy.xml & http://msdn.microsoft.com/en-us/library/cc645032(VS.95).aspx for further details</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </span> <span class="rem" style="color: rgb(0, 128, 0); ">/// The socket request will be denied if the client access policy file is not served or if the client /</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// port is denied in the client access policy file</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> SL_SocketPortPolicyListener { TcpListener _Listener = <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>; TcpClient _Client = <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>; <span class="kwrd" style="color: rgb(0, 0, 255); ">const</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">string</span> _PolicyRequestString = <span class="str" style="color: rgb(0, 96, 128); ">"<policy-file-request/>"</span>; <span class="kwrd" style="color: rgb(0, 0, 255); ">int</span> _ReceivedLength = 0; <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[] _Policy = <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>; <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[] _ReceiveBuffer = <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>; EventLog eventLog; <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Initializes a new instance of the <see cref="SL_SocketPortPolicyListener"/> class.</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="serviceEventLog">The service event log.</param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> SL_SocketPortPolicyListener(EventLog serviceEventLog) { eventLog = serviceEventLog; Start(); }<span style="color: rgb(255, 0, 0); "> <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 增加的代码</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> SL_SocketPortPolicyListener() : <span class="kwrd" style="color: rgb(0, 0, 255); ">this</span>(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> EventLog(<span class="str" style="color: rgb(0, 96, 128); ">"Application"</span>)) { }</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Starts this instance.</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Start() { <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { <span class="rem" style="color: rgb(0, 128, 0); ">//增加的代码</span><strong><span style="color: rgb(255, 0, 0); "> var policyConfig = <span class="str" style="color: rgb(0, 96, 128); ">"<?xml version=\"1.0\" encoding =\"utf-8\"?>"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"<access-policy>"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"<cross-domain-access>"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"<policy>"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"<allow-from>"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"<domain uri=\"*\" />"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"</allow-from>"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"<grant-to>"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"<socket-resource port=\"4502-4530\" protocol=\"tcp\" />"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"</grant-to>"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"</policy>"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"</cross-domain-access>"</span> + <span class="str" style="color: rgb(0, 96, 128); ">"</access-policy>"</span>;</span></strong> <span class="rem" style="color: rgb(0, 128, 0); ">//删除的代码</span> <span class="rem" style="color: rgb(0, 128, 0); ">//string executionLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);</span> <span class="rem" style="color: rgb(0, 128, 0); ">//string policyFile = ConfigurationManager.AppSettings["PolicyFilePath"];</span> <span class="rem" style="color: rgb(0, 128, 0); ">//using(FileStream fs = new FileStream(executionLocation + policyFile, FileMode.Open))</span> <span class="rem" style="color: rgb(0, 128, 0); ">//{</span> <span class="rem" style="color: rgb(0, 128, 0); ">// _Policy = new byte[fs.Length];</span> <span class="rem" style="color: rgb(0, 128, 0); ">// fs.Read(_Policy, 0, _Policy.Length);</span> <span class="rem" style="color: rgb(0, 128, 0); ">//}</span> <span class="rem" style="color: rgb(0, 128, 0); ">//增加的代码</span> <span style="color: rgb(255, 0, 0); "><strong>_Policy = Encoding.Default.GetBytes(policyConfig);</strong></span> _ReceiveBuffer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[_PolicyRequestString.Length]; <span class="rem" style="color: rgb(0, 128, 0); ">//Using TcpListener which is a wrapper around a Socket</span> <span class="rem" style="color: rgb(0, 128, 0); ">//Allowed port is 943 for Silverlight sockets policy data</span> _Listener = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> TcpListener(IPAddress.Any, 943); _Listener.Start(); _Listener.BeginAcceptTcpClient(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(OnBeginAccept), <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(Exception exp) { LogError(exp); } } <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Called when [begin accept].</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="ar">The ar.</param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">private</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> OnBeginAccept(IAsyncResult ar) { _Client = _Listener.EndAcceptTcpClient(ar); _Client.Client.BeginReceive(_ReceiveBuffer, 0, _PolicyRequestString.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(OnReceiveComplete), <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>); } <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Called when [receive complete].</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="ar">The ar.</param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">private</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> OnReceiveComplete(IAsyncResult ar) { <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { _ReceivedLength += _Client.Client.EndReceive(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//See if there's more data that we need to grab</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">if</span>(_ReceivedLength < _PolicyRequestString.Length) { <span class="rem" style="color: rgb(0, 128, 0); ">//Need to grab more data so receive remaining data</span> _Client.Client.BeginReceive(_ReceiveBuffer, _ReceivedLength, _PolicyRequestString.Length - _ReceivedLength, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(OnReceiveComplete), <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>); <span class="kwrd" style="color: rgb(0, 0, 255); ">return</span>; } <span class="rem" style="color: rgb(0, 128, 0); ">//Check that <policy-file-request/> was sent from client</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">string</span> request = System.Text.Encoding.UTF8.GetString(_ReceiveBuffer, 0, _ReceivedLength); <span class="kwrd" style="color: rgb(0, 0, 255); ">if</span>(StringComparer.InvariantCultureIgnoreCase.Compare(request, _PolicyRequestString) != 0) { <span class="rem" style="color: rgb(0, 128, 0); ">//Data received isn't valid so close</span> _Client.Client.Close(); <span class="kwrd" style="color: rgb(0, 0, 255); ">return</span>; } <span class="rem" style="color: rgb(0, 128, 0); ">//Valid request received....send policy file</span> _Client.Client.BeginSend(_Policy, 0, _Policy.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(OnSendComplete), _Client.Client); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(Exception exp) { _Client.Client.Close(); LogError(exp); } _ReceivedLength = 0; <span class="rem" style="color: rgb(0, 128, 0); ">//listen for the next client</span> _Listener.BeginAcceptTcpClient(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(OnBeginAccept), <span class="kwrd" style="color: rgb(0, 0, 255); ">null</span>); } <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Called when [send complete].</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="ar">The ar.</param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">private</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> OnSendComplete(IAsyncResult ar) { Socket socket = (Socket)ar.AsyncState; <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { socket.EndSend(ar); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(Exception exp) { LogError(exp); } <span class="kwrd" style="color: rgb(0, 0, 255); ">finally</span> { socket.Close(); } } <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Logs the error.</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="exp">The exp.</param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">private</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> LogError(Exception exp) { eventLog.WriteEntry(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>.Format(<span class="str" style="color: rgb(0, 96, 128); ">"Error in PolicySocketServer: {0} \r\n StackTrace: {1}"</span>, exp.Message, exp.StackTrace)); } }}
然后,在SocketServer的主程序中,加入下面的代码(只需要添加红色这一行即可)
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="rem" style="color: rgb(0, 128, 0); ">//额外导入的两个命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketServer{ <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> Program { <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// Socket Server 演示</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> Main(<span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>[] args) { <strong><span style="color: rgb(255, 0, 0); ">var policyServer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> SocketServerService.SL_SocketPortPolicyListener();</span></strong> <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个新的Socket,这里我们使用最常用的基于TCP的Stream Socket(流式套接字)</span> var socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">//将该socket绑定到主机上面的某个端口</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.bind.aspx</span> socket.Bind(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> IPEndPoint(IPAddress.Any, 4530)); <span class="rem" style="color: rgb(0, 128, 0); ">//启动监听,并且设置一个最大的队列长度</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.listen(v=VS.100).aspx</span> socket.Listen(4); <span class="rem" style="color: rgb(0, 128, 0); ">//开始接受客户端连接请求</span> <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.beginaccept.aspx</span> socket.BeginAccept(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ClientAccepted), socket); Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"Server is ready!"</span>); Console.Read(); } <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> ClientAccepted(IAsyncResult ar) { var socket = ar.AsyncState <span class="kwrd" style="color: rgb(0, 0, 255); ">as</span> Socket; <span class="rem" style="color: rgb(0, 128, 0); ">//这就是客户端的Socket实例,我们后续可以将其保存起来</span> var client = socket.EndAccept(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//给客户端发送一个欢迎消息</span> client.Send(Encoding.Unicode.GetBytes(<span class="str" style="color: rgb(0, 96, 128); ">"Hi there, I accept you request at "</span> + DateTime.Now.ToString())); <span class="rem" style="color: rgb(0, 128, 0); ">//实现每隔两秒钟给服务器发一个消息</span> <span class="rem" style="color: rgb(0, 128, 0); ">//这里我们使用了一个定时器</span> var timer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> System.Timers.Timer(); timer.Interval = 2000D; timer.Enabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">true</span>; timer.Elapsed += (o, a) => { <span class="rem" style="color: rgb(0, 128, 0); ">//检测客户端Socket的状态</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">if</span>(client.Connected) { <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { client.Send(Encoding.Unicode.GetBytes(<span class="str" style="color: rgb(0, 96, 128); ">"Message from server at "</span> + DateTime.Now.ToString())); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(SocketException ex) { Console.WriteLine(ex.Message); } } <span class="kwrd" style="color: rgb(0, 0, 255); ">else</span> { timer.Stop(); timer.Enabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">false</span>; Console.WriteLine(<span class="str" style="color: rgb(0, 96, 128); ">"Client is disconnected, the timer is stop."</span>); } }; timer.Start(); <span class="rem" style="color: rgb(0, 128, 0); ">//接收客户端的消息(这个和在客户端实现的方式是一样的)</span> client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ReceiveMessage), client); <span class="rem" style="color: rgb(0, 128, 0); ">//准备接受下一个客户端请求</span> socket.BeginAccept(<span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ClientAccepted), socket); } <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[] buffer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[1024]; <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">static</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> ReceiveMessage(IAsyncResult ar) { <span class="kwrd" style="color: rgb(0, 0, 255); ">try</span> { var socket = ar.AsyncState <span class="kwrd" style="color: rgb(0, 0, 255); ">as</span> Socket; <span class="rem" style="color: rgb(0, 128, 0); ">//方法参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.endreceive.aspx</span> var length = socket.EndReceive(ar); <span class="rem" style="color: rgb(0, 128, 0); ">//读取出来消息内容</span> var message = Encoding.Unicode.GetString(buffer, 0, length); <span class="rem" style="color: rgb(0, 128, 0); ">//显示消息</span> Console.WriteLine(message); <span class="rem" style="color: rgb(0, 128, 0); ">//接收下一个消息(因为这是一个递归的调用,所以这样就可以一直接收消息了)</span> socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> AsyncCallback(ReceiveMessage), socket); } <span class="kwrd" style="color: rgb(0, 0, 255); ">catch</span>(Exception ex){ Console.WriteLine(ex.Message); } } }}
再次测试,我们就发现Silverlight客户端能够连接到服务器了
既然连接上了服务器,那么就让我们来将Silverlight客户端里面其他的一些功能都实现一下吧
第五步:实现Silverlight客户端的消息收发
<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Collections.Generic;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Linq;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Controls;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Documents;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Input;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Media;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Media.Animation;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Windows.Shapes;<span class="rem" style="color: rgb(0, 128, 0); ">//导入命名空间</span><span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Net.Sockets;<span class="kwrd" style="color: rgb(0, 0, 255); ">using</span> System.Text;<span class="kwrd" style="color: rgb(0, 0, 255); ">namespace</span> SocketSilverlightClient{ <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 演示如何在Silverlight中使用Socket技术</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 作者:陈希章</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">partial</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">class</span> MainPage : UserControl { <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> MainPage() { InitializeComponent(); } <span class="rem" style="color: rgb(0, 128, 0); ">//创建一个套接字</span> Socket socket = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 尝试连接到服务器</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="sender"></param></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="e"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">private</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> btConnect_Click(<span class="kwrd" style="color: rgb(0, 0, 255); ">object</span> sender, RoutedEventArgs e) { <span class="rem" style="color: rgb(0, 128, 0); ">//准备一个异步参数(这是特有的)</span> var args = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> SocketAsyncEventArgs(); <span class="rem" style="color: rgb(0, 128, 0); ">//设置远程服务器地址,这里用DnsSafeHost,可以获取到宿主远程服务器的主机名称</span> args.RemoteEndPoint = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> DnsEndPoint(App.Current.Host.Source.DnsSafeHost, 4530); <span class="rem" style="color: rgb(0, 128, 0); ">//注册Completed事件处理程序</span> args.Completed += ConnectCompleted; <span class="rem" style="color: rgb(0, 128, 0); ">//发起异步的连接请求</span> socket.ConnectAsync(args); } <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 该事件在连接成功时发生</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="sender"></param></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> ConnectCompleted(<span class="kwrd" style="color: rgb(0, 0, 255); ">object</span> sender, SocketAsyncEventArgs e) { <span class="kwrd" style="color: rgb(0, 0, 255); ">if</span>(e.SocketError > 0)<span class="rem" style="color: rgb(0, 128, 0); ">//0表示成功,其他的表示有错误</span> { <span class="rem" style="color: rgb(0, 128, 0); ">//注意,因为Completed方法是在工作线程触发的,所以要对主线程进行访问,必须使用Dispatcher机制</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">this</span>.Dispatcher.BeginInvoke(() => { MessageBox.Show(<span class="str" style="color: rgb(0, 96, 128); ">"Connect fail:"</span> + e.SocketError.ToString()); }); } <span class="kwrd" style="color: rgb(0, 0, 255); ">else</span> { <span class="kwrd" style="color: rgb(0, 0, 255); ">this</span>.Dispatcher.BeginInvoke(() => { <span class="rem" style="color: rgb(0, 128, 0); ">//MessageBox.Show("Connect success");</span> <span class="rem" style="color: rgb(0, 128, 0); ">//将连接按钮禁用掉</span> btConnect.Content = <span class="str" style="color: rgb(0, 96, 128); ">"Connected"</span>; btConnect.IsEnabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">false</span>; var buffer = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">byte</span>[1024]; e.SetBuffer(buffer, 0, buffer.Length); e.Completed -= ConnectCompleted; e.Completed += ReceiveCompleted; socket.ReceiveAsync(e); }); } } <span class="rem" style="color: rgb(0, 128, 0); ">/// <summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// 该事件在接收消息时发生</span> <span class="rem" style="color: rgb(0, 128, 0); ">/// </summary></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="sender"></param></span> <span class="rem" style="color: rgb(0, 128, 0); ">/// <param name="args"></param></span> <span class="kwrd" style="color: rgb(0, 0, 255); ">public</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> ReceiveCompleted(<span class="kwrd" style="color: rgb(0, 0, 255); ">object</span> sender, SocketAsyncEventArgs e) { <span class="rem" style="color: rgb(0, 128, 0); ">//将消息显示在界面上</span> var result = Encoding.Unicode.GetString(e.Buffer, 0, e.Count); <span class="kwrd" style="color: rgb(0, 0, 255); ">this</span>.Dispatcher.BeginInvoke(() => { icResult.Items.Add(result); }); <span class="rem" style="color: rgb(0, 128, 0); ">//递归继续接收消息</span> socket.ReceiveAsync(e); } <span class="kwrd" style="color: rgb(0, 0, 255); ">private</span> <span class="kwrd" style="color: rgb(0, 0, 255); ">void</span> btSend_Click(<span class="kwrd" style="color: rgb(0, 0, 255); ">object</span> sender, RoutedEventArgs e) { var args = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> SocketAsyncEventArgs(); <span class="rem" style="color: rgb(0, 128, 0); ">//将用户输入的文本转成字节</span> var buffer = Encoding.Unicode.GetBytes(txtInput.Text); args.SetBuffer(buffer, 0, buffer.Length); <span class="rem" style="color: rgb(0, 128, 0); ">//设置远程服务器地址,这里用DnsSafeHost,可以获取到宿主远程服务器的主机名称</span> args.RemoteEndPoint = <span class="kwrd" style="color: rgb(0, 0, 255); ">new</span> DnsEndPoint(App.Current.Host.Source.DnsSafeHost, 4530); <span class="rem" style="color: rgb(0, 128, 0); ">//发送完成的话,将控件清空,激活</span> args.Completed += (o, a) => { <span class="kwrd" style="color: rgb(0, 0, 255); ">this</span>.Dispatcher.BeginInvoke(() => { txtInput.Text = <span class="kwrd" style="color: rgb(0, 0, 255); ">string</span>.Empty; btSend.IsEnabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">true</span>; }); }; <span class="rem" style="color: rgb(0, 128, 0); ">//禁用按钮</span> btSend.IsEnabled = <span class="kwrd" style="color: rgb(0, 0, 255); ">false</span>; <span class="rem" style="color: rgb(0, 128, 0); ">//发送消息</span> socket.SendAsync(args); } }}
运行起来看看吧
还不错对吧,这个例子给大家演示了如何在Silverlight中使用Socket,接下来大家可以结合自己的现实工作做一些研究和扩展吧
本文完整代码如下 http://files.cnblogs.com/chenxizhang/SocketWorkshop(with-silverlight).rar
- VS2010 C# 你得学会并且学得会的Socket编程基础知识(Silverlight Socket编程)
- VS2010 C# 你得学会并且学得会的Socket编程基础知识(Silverlight Socket编程)
- 你得学会并且学得会的Socket编程基础知识
- 你得学会并且学得会的Socket编程基础知识
- 你得学会并且学得会的Socket编程基础知识
- 你得学会并且学得会的Socket编程基础知识
- 你得学会并且学得会的Socket编程基础知识
- 你得学会并且学得会的Socket编程基础知识
- 你得学会并且学得会的Socket编程基础知识(续)——Silverlight客户端
- Socket编程的基础知识
- C#的Socket编程
- 学会在linux下的socket 编程
- Socket编程基础知识
- Socket编程基础知识
- Socket编程基础知识
- Socket编程基础知识
- socket编程之基础知识
- socket编程基础知识
- PB数据窗口其他知识
- MacOS 下安装Gerrit
- 通过Jetty搭建一个简单的Servlet运行环境
- Oralce 日期函数
- java 对象 与json字符串的相互转化
- VS2010 C# 你得学会并且学得会的Socket编程基础知识(Silverlight Socket编程)
- 解决alaert.builder二次调用报错的bug
- emacs在win8乱码
- 16.0~16.8 多任务 后台运行 Multitasking
- android 判断点击的位置是不是在指定的view上
- 集团信息化之路——关于网络电子采购系统的需求报告
- Implied do loop of FORTRAN
- Android textView 跑马灯效果
- 经纬财富:乐平天通银价格上方遇阻 关注晚间会议纪要