原文 http://www.cnblogs.com/ZetaChow/archive/2009/05/16/2237347.html

刚接触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

<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>

代码:

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();

}

}

}

服务器端,创建一个控制台项目

代码:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Net.Sockets;

using System.Net;

using System.Threading;

using System.IO;

namespace ConsoleApp

{

class Program

{

static void Main(string[] args)

{

Console.WriteLine("================Socket服务开启======================");

//建立一个子线程,用于创建Socket来监听策略请求和发送。

ThreadStart pcts = new ThreadStart(PolicyThread);

Thread policythread = new Thread(pcts);

policythread.Start();

//建立一个子线程,用于创建Socket来监听信息请求和发送。

ThreadStart infots = new ThreadStart(InfoThread);

Thread infothread = new Thread(infots);

infothread.Start();

}

//监听策略请求和发送策略请求方法

static void PolicyThread()

{

//创建一个Socket用来监听943(固定的)端口的策略请求

Socket policy = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

policy.Bind(new IPEndPoint(IPAddress.Any, 943));

policy.Listen(10);

//无限循环监听

while (true)

{

if (policy.Blocking)//如果Socket是阻止模式的(这个东西实际上可以用不)

{

//创建Socket,用来获取监听Socket的第一个Socket链接

Socket _policy = policy.Accept();

//定义一个字符串,该字符串与Silverlight发送过来的请求字符串一样。

string policyRequestString = "<policy-file-request/>";

//定义一个字节数组

byte[] b = new byte[policyRequestString.Length];

//将客户端发送过来,服务器接收到的字节数组存入b中

_policy.Receive(b);

//将接收到的字节数组转换成字符串

string requeststring = System.Text.Encoding.UTF8.GetString(b, 0, b.Length);

//显示客户端发送的字符串

Console.WriteLine(requeststring);

//比对客户端发送过来的字符串是否和之前定义的额定好的策略请求字符串相同,如果相同,说明该请求是一个策略请求。

if (requeststring == policyRequestString)

{

//如果客户端发送的是一个策略请求,服务器发送策略文件到客户端

SendPolicy(_policy);

Console.WriteLine("Policy File have sended");

//关闭当前连接Socket

_policy.Close();

}

else// 否则,显示错误

{

Console.WriteLine("not a sure request string!");

}

}

}

}

//监听信息请求和发送信息方法

static void InfoThread()

{

//创建一个Socket用于监听4502端口,获取接收客户端发送过来的信息

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

socket.Bind(new IPEndPoint(IPAddress.Any, 4502));

socket.Listen(10);

//无线循环监听

while (true)

{

//创建Socket,用来获取监听Socket的第一个Socket链接

Socket _socket = socket.Accept();

//创建一个空字节数组

byte[] b2 = new byte[1024];

//将接受到的字节数组存入到之前定义的b2字节数组中。

_socket.Receive(b2);

//显示接收到的信息

Console.WriteLine(Encoding.UTF8.GetString(b2));

//发回一个信息给客户端,该信息是字节数组,所以我们将信息字符串转换成字节数组

_socket.Send(Encoding.UTF8.GetBytes("This Send Over!!"));

//关闭当前Socket连接

_socket.Close();

}

}

//发送策略文件的方法

//参数是传递进来的Socket连接

static void SendPolicy(Socket socket)

{

//创建一个文件流,该文件留指定代开一个策略文件,至于策略文件的格式,MS的Silverlight有详细说明和配置方法

FileStream fs = new FileStream(@"D:/WebSites/SilverLight/ConsoleApp/bin/Debug/PolicyFile.xml",FileMode.Open);

int length = (int)fs.Length;

byte[] bytes = new byte[length];

//将策略文件流读到上面定义的字节数组中

fs.Read(bytes,0,length);

//关闭文件流

fs.Close();

//其策略文件的字节数组发送给客户端

socket.Send(bytes,length,SocketFlags.None);

}

}

}

结束,这样就可以创建一个简单的Silverlight Socket收发程序了。其中还有许多需要改进的地方。但是已经很能说明Socket收发的过程和方法了,另外,服务器端最还还是用异步方法进行监听,这样在多并发的时候比较有效率。

Silverlight Socket 实现收发信息的更多相关文章

  1. Linux Kernel ‘/net/socket.c’本地信息泄露漏洞

    漏洞名称: Linux Kernel ‘/net/socket.c’本地信息泄露漏洞 CNNVD编号: CNNVD-201312-037 发布时间: 2013-12-04 更新时间: 2013-12- ...

  2. Android笔记:Socket客户端收发数据

    client.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" and ...

  3. 一个socket发送调试信息的类

    using UnityEngine; using System.Collections; using System; using System.Net.Sockets; using System.Ne ...

  4. 多线程socket UDP收发数据

    多线程socket收发数据 from threading import Thread from socket import * def sendData(): while True: sendInfo ...

  5. socket数据收发

    socket读写 TCP协议是面向流的,read和write调用的返回值往往小于参数指定的字节数.对于read调用,如果接收缓冲区中有20字节,请求读100个字节,就会返回20.对于write调用,如 ...

  6. python+socket实现网络信息交互及文件传输

    Socket 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket又称"套接字",应用程序通常通过"套接字" ...

  7. python网络编程——使用UDP、TCP协议收发信息

    UDP UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送. UDP传输数据时有大小限制,每个被传输的数据报必须限定在64KB之内. UDP ...

  8. Python建立socket并获取信息

    import socket, sys port = 80 host = "www.baidu.com" print "Creating socket..." s ...

  9. SpringCloud stream连接RabbitMQ收发信息

    百度上查的大部分都是一些很简单的单消费者或者单生产者的例子,并且多是同一个服务器的配置,本文的例子为多服务器配置下的消费生产和消费者配置. 参考资料:https://docs.spring.io/sp ...

随机推荐

  1. git管理修改

    为什么Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件. 新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删了一些又加了一些,也是一个修改 ...

  2. 库函数strlen源码重现及注意问题

    首先直接上源码: size_t strlen (const char * str) { const char *eos = str; while(*eos++); return(eos - str - ...

  3. PARTITION(number theory) ALSO Explosive number in codewars

    问题出于codewars,简言之:寻找和为一个整数的的不同整数组合.https://en.wikipedia.org/wiki/Partition_(number_theory) 例如:和为6的整数组 ...

  4. PHP和C#可共用的可逆加密算法

    PHP 加密用法 <?phpclass DES{    var $key;    var $iv; //偏移量        function DES($key = '11001100', $i ...

  5. MySql中游标使用总是多循环一次的解决方法

    CREATE DEFINER = 'root'@'%' PROCEDURE deyestest.procedure2() BEGIN DECLARE v_id INT; DECLARE v_userN ...

  6. html5重力感应事件

    if (window.DeviceMotionEvent) { window.addEventListener('devicemotion',deviceMotionHandler, false); ...

  7. Python简明教程---学习笔记

    字符双引号括起,数字不括: 分隔符为逗号(,),不能为空格 变量定义时即赋值 采用utf-8编码:#-*-coding:utf-8-*-或者#coding:utf-8 字符串定义:单/双引号括起 %符 ...

  8. linux---finger命令

    问题:CentOS7默认是没有安装finger这个程序的,所以finger命令执行不了. 解决方案: 1.安装finger yum -y install finger

  9. mysql memcache

    http://blog.csdn.net/newjueqi/article/details/8350643

  10. C/C++ 用libcurl库进行http通讯网络编程

    C/C++ 用libcurl库进行http通讯网络编程 目录索引: 一.LibCurl基本编程框架 二.一些基本的函数 三.curl_easy_setopt函数部分选项介绍 四.curl_easy_p ...