软件下载 | 资讯教程 | 最近更新 | 下载排行 | 一键转帖 | 发布投稿
您的位置:最火下载站 > 电脑教程 > 编程开发 > .NET技术 > Silverlight Socket 实现收发信息

Silverlight Socket 实现收发信息

刚接触Silverlight的时候,除了其异步应用WCF、流媒体、动画效果等方面外,Socket是最另我兴奋的功能。

在Web上实现Socket虽然不是什么新鲜事了,Activex,flash等都可以实现这样的效果,但是Silverlight这样方便的运用Socket让服务器与客户端通信确是我之前没有体验过的。

用它可以做什么?可以连线式的让服务器与客户端交互,而且,是在Web上,那么Web开发游戏,语音,视频聊天等都可以基于Socket功能实现,另外,服务器端是独立出来的,不依赖IIS进程,这样让数据之间的交互更自由。

废话不说,下面来看看如何实现

首先,在进行数据交换之前,我们必须明白Silverlight Socket的一些规矩和原则。

Silverlight客户端的Socket都是异步的,这点很容易明白,另外就是,考虑到Silverlight是应用到Web上的,而Silverlight的Socket自然就有一些安全限制。

每一个请求到服务器端的新的Socket连接会话Silverlight都会先悄悄的用另一个Socket去请求策略文件,这是很多刚接触Silverlight Socket的人感到郁闷的地方,请求策略时,Silverlight会自己发送一个字符串<policy-file-request/>到服务器的943端口,然后你必须在服务器程序里接收该请求,分析是否是策略请求后,发送一个策略文件的字符串给客户端,客户端接收到策略文件后自己分析完后再发送程序员自己写的数据请求。

客户端的策略请求是自动发送的,策略文件的接收和分析也是自动的,是Silverlight自发工作的,不需要程序员手工写代码进行发送接收和分析。

但是,服务器端接收策略请求需要手工完成,程序员必须创建一个Socket监听943端口(该端口是固定的,客户端策略请求固定发送到该端口),然后分析请求过来的数据是否是策略请求,如果是的,那么就读取策略文件,再将该策略文件发送到客户端就可以了。

另外一个限制,Silverlight Socket 数据交换端口必须在4502-4534范围,也就是说,整个Socket将用到两个端口,一个是943用于策略请求,另一个是4502-4534范围的你指定的数据交换端口。

不管你的Socket代码是如何工作,第一次在连接之前,Silverlight都会发送策略请求,只有成功接收到服务器返回的策略文件后,你的Socket代码才能进行工作,所以在第一次连接的时候,实际上Silverlight是进行了两次Socket,第一次请求策略,成功才进行你的Socket,因此,服务器端必要监听两个端口,但是两个监听可以分开在两个线程上工作(两个线程,不是两个进程)。每个会话请求一次策略后,之后的请求就不会再请求策略了,所以他们不能是线性的工作,而是两个独立的监听,否则会阻塞。

我的服务器端的策略监听和数据监听是用的两个子线程运行,而MS的示例是用的异步方法,都是为了不相互阻塞,用MS的方式也许更有效率些,而我是为了让代码更容易理解。

客户端实现了将文本框的内容发送到服务器端,然后服务器收到后显示出来,然后发回一句字符串,关闭连接,客户端收到服务器端的信息后也关闭连接。就这么简单

好后,具体看看示例,说明很详细。

客户端

建立一个Silverlight项目

XAML 

Copy to ClipboardLiehuo.Net Codes引用的内容:[www.veryhuo.com]
<UserControl x:Class="SilverlightTest.Socket1"

xmlns="http://schemas.microsoft.com/client/2007"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Width="400" Height="300">

<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">

<Grid.RowDefinitions >

<RowDefinition />

<RowDefinition />

</Grid.RowDefinitions>

<TextBox x:Name="txtToSend" Grid.Row="0"/>

<Button Grid.Row="1" Click="OnSend" Content="Send" Margin="20" />

</Grid>

</UserControl>

代码:

Copy to ClipboardLiehuo.Net Codes引用的内容:[www.veryhuo.com]
using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using System.Net.Sockets;

using System.Threading;

using System.Text;

namespace SilverlightTest

{

public partial class Socket1 : UserControl

{

public Socket1()

{

InitializeComponent();

}

//定义一个可在全局使用的Socket

System.Net.Sockets.Socket socket;

//定义一个同步上下文类,用来将子线程的操作调度到主线程上以可控制UI属性。

SynchronizationContext syn;

//发送信息按钮的单击事件

void OnSend(object sender, EventArgs args)

{

//定义一个字节数组,并将文本框的的类容转换为字节数组后存入

byte[] bytes = Encoding.UTF8.GetBytes(txtToSend.Text);

//显示信息,可不要。

txtToSend.Text += "\r\nDnsSafeHost:"+Application.Current.Host.Source.DnsSafeHost;

//将同步上下文设置在当前上下文(线程,主线程,可控制UI的)

syn = SynchronizationContext.Current;

//为socket创建示例,并设置相关属性。

socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);

//定义并实例一个Socket参数

SocketAsyncEventArgs socketArgs = new SocketAsyncEventArgs();

//设置到远程终节点属性(4502端口,为什么是4502,MS的SL通信安全上有)

socketArgs.RemoteEndPoint = new DnsEndPoint(Application.Current.Host.Source.DnsSafeHost, 4502);

//设置好当Socket任何一个动作完成时的回调函数。

socketArgs.Completed += new EventHandler<SocketAsyncEventArgs>(socketArgs_Completed);

//Socket参数的用户标识,实际上就是一个可以传递的OBJECT参数。

socketArgs.UserToken = bytes;

//执行连接。

socket.ConnectAsync(socketArgs);

}

void socketArgs_Completed(object sender, SocketAsyncEventArgs e)

{

//当任何一个Socket动作完成,都回调该函数,然后对LastOperation进行判断后继续执行相应的部分

switch (e.LastOperation)

{

case SocketAsyncOperation.Connect:

ProcessConnect(e);

break;

case SocketAsyncOperation.Receive:

ProcessReceive(e);

break;

case SocketAsyncOperation.Send:

ProcessSend(e);

break;

}

}

//将数据放入buffer并进行异步发送

void ProcessConnect(SocketAsyncEventArgs e)

{

//当连接成功后,获取Socket参数 e传递过来的用户标识(也就是本示例中用户输入的字符串转换的Byte字节数组)

byte[] bytes = (byte[])e.UserToken;

//设置Socket参数的缓冲区参数,将我们的字节数组设置为Socket的缓冲区。

e.SetBuffer(bytes, 0, bytes.Length);

//同步一下上下文,显示一下当前的状态信息。

syn.Post(GetText,"States:"+e.SocketError.ToString()+","+e.LastOperation.ToString());

//发送数据

socket.SendAsync(e);

}

//发送完成后,执行等待接收服务器发回的数据

void ProcessSend(SocketAsyncEventArgs e)

{

//定义个空的字节数组,设置好其大小

byte[] bytes = new byte[1024];

//将前面定义字节数组设置成缓冲区

e.SetBuffer(bytes, 0, bytes.Length);

//执行异步接收

socket.ReceiveAsync(e);

}

//当接收完成后

void ProcessReceive(SocketAsyncEventArgs e)

{

//在执行好接收后,本地SOCKET的缓冲区就会被服务器发送的数据填充。

//显示下信息,当然也是用同步上下文的方式,在显示信息的时候,就直接将缓冲区的字节数组转换成字符串。

syn.Post(GetText, Encoding.UTF8.GetString(e.Buffer, 0,e.Buffer.Length)+" and Received" );

//关闭Socket连接

socket.Close();

//最后显示下,Socket关闭。

syn.Post(GetText,"Socket Closed");

}

//同步上下文调用的方法。

void GetText(object str)

{

txtToSend.Text +="\r\n"+ str.ToString();

}
}
}

相关阅读
栏目导航
推荐软件