十个月的宝宝把手机钢化膜怎么取下来咬碎了有事吗

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

我要回帖

更多关于 钢化膜怎么取下来 的文章

 

随机推荐