Silverlight Socket通信学习笔记

Silverlight Socket通信学习笔记,第1张

概述      之前因为项目的关系,涉及到与服务器实时通信,比如通过GPRS将GPS的位置信息等信息发送到服务器,然后再转发给Silverlight应用程序,最后在地图上标示出实时的地理位置,查了查相关的资料,网上给出的比较好的方法就是利用Socket与服务器通信。于是这两天看了看Silverlight下的Socket通信,在此将学习的心得和实现过程作一个记录,以供相互学习和交流。       园子里

      之前因为项目的关系,涉及到与服务器实时通信,比如通过GPRS将GPS的位置信息等信息发送到服务器,然后再转发给Silverlight应用程序,最后在地图上标示出实时的地理位置,查了查相关的资料,网上给出的比较好的方法就是利用Socket与服务器通信。于是这两天看了看Silverlight下的Socket通信,在此将学习的心得和实现过程作一个记录,以供相互学习和交流。

      园子里关于这方面的内容已经有很多大神写过了,这里小小的推荐一下:

      http://www.cnblogs.com/webabcd/archive/2008/12/22/1359551.HTML

      因此本文的重点知识说一下具体实现的过程,细节和原理性的东西不会太多,因为本人也是新手,所以就不卖弄了。之前说到和地图结合,所以本文的后续工作将会把Silverlight的Socket通信与ArcGIS 的地图结合,来实现一个小小的功能,而本篇则主要关于Socket的实现过程。下面就进入正题吧。

 

一.Silverlight的Socket通信和控制台、WinForm下的Socket通信有很大的区别。

对于后两者的Socket通信,其过程就是开启端口,绑定端口,监听端口,连接,接收数据,发送数据。

而在Silverlight中则不太一样,在Silverlight中,首先是Silverlight客户端自动向943端口的服务器端发送一个“<policy-file-request/>”的语句请求,然后服务器端向客户端发送策略文件:

clIEntaccesspolicy.xml,例如:

<?xml version="1.0" enCoding="utf-8" ?>  <access-policy>    <cross-domain-access>      <policy>        <allow-from>          <domain uri="*"/>        </allow-from>        <grant-to>          <socket-resource port="4502-4534" protocol="tcp"/>        </grant-to>      </policy>    </cross-domain-access>  </access-policy>

发送之后,才允许和服务器进行Socket通信,之后的过程则都是一样。

@H_502_121@二、服务器端

2.1、Silverligh中发送策略文件服务

上面说到,Silverlight中,服务器端会向客户端发送策略文件,然后才能开始Socket通信,下面给出服务器端的发送策略文件服务的代码,该代码是在网上找的,是别人已经写好的一个类,所以在编写Silverlight 的Socket通信程序时,只要添加这个类就好了,代码如下:

using System;  using System.Net.sockets;  using System.Net;  using System.Threading;  using System.IO;  using System.windows.Forms;    namespace windowsServer  {      class PolicySocketServer      {          TcpListener _Listener = null;          TcpClIEnt _ClIEnt = null;          static ManualresetEvent _TcpClIEntConnected = new ManualresetEvent(false);          const string _PolicyRequestString = "<policy-file-request/>";          int _ReceivedLength = 0;          byte[] _Policy = null;          byte[] _ReceiveBuffer = null;            private voID InitializeData()          {              string policyfile = Path.Combine(Application.StartupPath,"clIEntaccesspolicy.xml");              using (fileStream fs = new fileStream(policyfile,fileMode.Open))              {                  _Policy = new byte[fs.Length];                  fs.Read(_Policy,0,_Policy.Length);              }              _ReceiveBuffer = new byte[_PolicyRequestString.Length];          }          public voID StartSocketServer()          {              InitializeData();                try              {                  _Listener = new TcpListener(IPAddress.Any,943);                  _Listener.Start();                  while (true)                  {                      _TcpClIEntConnected.reset();                      _Listener.BeginAcceptTcpClIEnt(new AsyncCallback(OnBeginAccept),null);                      _TcpClIEntConnected.WaitOne();                  }              }              catch (Exception)              {              }          }            private voID OnBeginAccept(IAsyncResult ar)          {              _ClIEnt = _Listener.EndAcceptTcpClIEnt(ar);              _ClIEnt.ClIEnt.BeginReceive(_ReceiveBuffer,_PolicyRequestString.Length,SocketFlags.None,new AsyncCallback(OnReceiveComplete),null);          }            private voID OnReceiveComplete(IAsyncResult ar)          {              try              {                  _ReceivedLength += _ClIEnt.ClIEnt.EndReceive(ar);                  if (_ReceivedLength < _PolicyRequestString.Length)                  {                      _ClIEnt.ClIEnt.BeginReceive(_ReceiveBuffer,_ReceivedLength,_PolicyRequestString.Length - _ReceivedLength,null);                      return;                  }                  string request = System.Text.EnCoding.UTF8.GetString(_ReceiveBuffer,0,_ReceivedLength);                  if (StringComparer.InvariantCultureIgnoreCase.Compare(request,_PolicyRequestString) != 0)                  {                      _ClIEnt.ClIEnt.Close();                      return;                  }                  _ClIEnt.ClIEnt.BeginSend(_Policy,_Policy.Length,new AsyncCallback(OnSendComplete),null);              }              catch (Exception)              {                  _ClIEnt.ClIEnt.Close();              }              _ReceivedLength = 0;              _TcpClIEntConnected.Set(); //Allow waiting thread to proceed           }            private voID OnSendComplete(IAsyncResult ar)          {              try              {                  _ClIEnt.ClIEnt.EndSendfile(ar);              }              catch (Exception)              {              }              finally              {                  _ClIEnt.ClIEnt.Close();              }          }       }  }

2.2、启动策略文件服务,声明Socket,监听端口,接收数据,发送数据。

启动策略文件服务

#region Start The Policy Server 验证策略文件              PolicySocketServer StartPolicyServer = new PolicySocketServer();              Thread th = new Thread(new ThreadStart(StartPolicyServer.StartSocketServer));              th.IsBackground = true;              th.Start();              #endregion 

声明Socket,绑定端口,开始监听

 private voID Startbutton_Click(object sender,EventArgs e)          {//创建Socket              Listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);              //获取主机信息              IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostname());                //把IP和端口转换化为IPEndPoint实例,端口号取4530              //Win7 中开启了IPV6的地址,因此0,1对应的是IPV6的地址,2,3对应IPV4地址,3对应本机的IP地址              //XP中没有开启IPV6              HostIPTextBox.Text = ipHostInfo.AddressList[3].ToString();                if (!string.IsNullOrEmpty(PortTextBox.Text))              {                  //获取端口号                  int port = Convert.ToInt32(PortTextBox.Text.Trim());                  //获得本机的IP地址                  localEP = new IPEndPoint(ipHostInfo.AddressList[3],port);              }              else              {                 //默认4530端口                  ipAddress = IPAddress.Parse("127.0.0.1");                  localEP = new IPEndPoint(ipHostInfo.AddressList[3],4530);              }                try              {                  //绑定指定的终结点                  Listener.Bind(localEP);                  //开始监听                  Listener.Listen(10);                  //一直循环接收客户端的消息,开启监听端口线程                  ThreadStart threaDWatchStart = new ThreadStart(WatchConnecting);                  threaDWatch = new Thread(threaDWatchStart);                  threaDWatch.IsBackground = true;                  threaDWatch.Start();              }              catch (Exception ex)              {                  MessageBox.Show(ex.Data.ToString());              }          }

连接端口,接收数据

   private voID WatchConnecting()          {              ChangeStatue("等待Silverlight客户端连接.....");              while (true)  //持续不断监听客户端发来的请求                {                  Listener.BeginAccept(AcceptCallBack,Listener);                  _flipFlop.WaitOne();              }          }
 private  voID AcceptCallBack(IAsyncResult asyresult)          {              Socket Listener = (Socket)asyresult.AsyncState;              Socket socket = Listener.EndAccept(asyresult);              ChangeStatue("连接到Silverlight客户端....");              _flipFlop.Set();              var state = new StateObject();              state.socket = socket;              socket.BeginReceive(state.Buffer,0,StateObject.BufferSize,ReciverCallBack,state);          }
  private voID ReciverCallBack(IAsyncResult asyResult)          {              StateObject state = (StateObject)asyResult.AsyncState;              Socket socket = state.socket;              int read = socket.EndReceive(asyResult);              if (read > 0)              {                  string chunk = EnCoding.UTF8.GetString(state.Buffer,read);                  state.StringBuilder.Append(chunk);                  if (state.StringBuilder.Length > 0)                  {                      string result = state.StringBuilder.ToString();                      ChangeStatue("成功接收到消息:"+result);                      ChangeReciveText(result);                      Send(socket,SendTextBox.Text);                      AddListItems("接收消息:"+result+"\n");                      AddListItems("发送消息:" + SendTextBox.Text + "\n");                  }              }          }

发送数据

 private voID Send(Socket handler,String data)          {              byte[] byteData = EnCoding.UTF8.GetBytes(data);              handler.BeginSend(byteData,byteData.Length,0,new AsyncCallback(SendCallBack),handler);          }            private voID SendCallBack(IAsyncResult asyResult)          {              try              {                  Socket handler = (Socket)asyResult.AsyncState;                  int byteSent = handler.EndSend(asyResult);                  if (byteSent > 0)                  {                      ChangeStatue("发送数据成功!");                  }              }              catch (Exception ex)              {                  MessageBox.Show(ex.Data.ToString());              }          }

StateObject类:

 public class StateObject      {          public Socket Socket;          public StringBuilder StringBuilder = new StringBuilder();          public const int BufferSize = 1024;          public byte[] Buffer = new byte[BufferSize];          public int TotalSize;      }

@H_502_121@客户端:

 和服务器端类似,客户端的 *** 作包括:声明Socket,指定服务器地址和端口,连接到指定的服务器端口,发送数据,接收数据。

下面是具体的实现代码:

声明Socket

 

private Socket socket;

 

指定服务器地址和端口,开始连接

  private voID Sendbutton_Click(object sender,RoutedEventArgs e)          {              if(string.IsNullOrEmpty(IPTextBox.Text)||string.IsNullOrEmpty(PortTextBox.Text))              {                  MessageBox.Show ("请输入主机IP地址和端口号!");                  return;              }              //ip地址              string host=IPTextBox.Text.Trim();              //端口号              int port=Convert.ToInt32(PortTextBox.Text.Trim());              //建立终结点对象              DnsEndPoint hostEntry=new DnsEndPoint(host,port);              //创建一个Socket对象              socket=new Socket(AddressFamily.InterNetwork,ProtocolType.Tcp);              //创建Socket异步事件参数              socketasynceventargs socketEventArg=new socketasynceventargs ();              //将消息转化为发送的byte[]格式              byte[]buffer=EnCoding.UTF8.GetBytes(MessageTextBox.Text);              //注册Socket完成事件              socketEventArg.Completed+=new EventHandler<socketasynceventargs>(socketEventArg_Completed);              //设置Socket异步事件远程终结点              socketEventArg.RemoteEndPoint=hostEntry;              //将定义好的Socket对象赋值给Socket异步事件参数的运行实例属性              socketEventArg.UserToken = buffer;              try              {                  socket.ConnectAsync(socketEventArg);              }              catch(SocketException ex)              {                  throw new SocketException((int)ex.ErrorCode);              }          }

向服务器发送数据,并接受服务器回复的消息。

 private voID socketEventArg_Completed(object sender,socketasynceventargs e)          {             //检查是否发送出错              if (e.socketError != SocketError.Success)              {                  if (e.socketError == SocketError.ConnectionAborted)                  {                      dispatcher.BeginInvoke(() => MessageBox.Show("连接超时....请重试!"));                  }                  else if (e.socketError == SocketError.ConnectionRefused)                  {                      dispatcher.BeginInvoke(() => MessageBox.Show("无法连接到服务器端:"+e.socketError));                  }else                  {                      dispatcher.BeginInvoke(() => MessageBox.Show("出错了!"+e.socketError));                  }                  return;              }             //如果连接上,则发送数据              if (e.Lastoperation == SocketAsyncoperation.Connect)              {                      byte[] userbytes = (byte[])e.UserToken;                      e.SetBuffer(userbytes,userbytes.Length);                      socket.SendAsync(e);                                    }//如果已发送数据,则开始接收服务器回复的消息              else if (e.Lastoperation == SocketAsyncoperation.Send)              {                  dispatcher.BeginInvoke(() =>                  {                      ListBox1.Items.Add("客户端在" + DateTime.Now.ToShortTimeString() + ",发送消息:" + MessageTextBox.Text);                  });                  byte[] userbytes = new byte[1024];                  e.SetBuffer(userbytes,userbytes.Length);                  socket.ReceiveAsync(e);              }//接收服务器数据              else if (e.Lastoperation == SocketAsyncoperation.Receive)              {                  string RecevIEStr = EnCoding.UTF8.GetString(e.Buffer,e.Buffer.Length).Replace("""",);                  dispatcher.BeginInvoke(()                   {                      ListBox1.Items.Add(=>"服务器在"" + DateTime.Now.ToShortTimeString() + ,回复消息:" RecevIEStr);                  });                  socket.Close();              }          }      +<

xaml代码:

UserControl      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"      xmlns:d="http://schemas.microsoft.com/Expression/blend/2008"      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      xmlns:esri="http://schemas.esri.com/arcgis/clIEnt/2009" x:Class="SilverlightSocket.MainPage"      mc:Ignorable="d"      d:DesignHeight="417" d:DesignWIDth="530"><        GrID x:name="LayoutRoot" Background="White"><          GrID.ColumnDeFinitions><              ColumnDeFinition WIDth="0.868*"/><              ColumnDeFinition WIDth="0.135*"/></          GrID.ColumnDeFinitions><          GrID.RowDeFinitions><              RowDeFinition/></          GrID.RowDeFinitions><          esri:Map Background="White" WrapAround="True" GrID.ColumnSpan="2"><              esri:ArcGISTiledMapServiceLayer Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/></          esri:Map><          StackPanel GrID.Column="1" Background="#7F094870"><              StackPanel.Effect><                  DropShadowEffect/></              StackPanel.Effect><              TextBlock x:name="textBlock1" Text="主机IP" GrID.Column="1" margin="5,5,0" Foreground="#FFE7D4E3" FontWeight="Bold"/> <              TextBox x:name="IPTextBox" Text="169.254.57.67" GrID.Column="1" d:LayoutOverrIDes="WIDth" margin="5,0" HorizontalAlignment="left"/><              TextBlock x:name="textBlock2" Text="端口号" GrID.Column="1" margin="5,0" Foreground="#FFE7D4E3" FontWeight="Bold"/> <              TextBox x:name="PortTextBox" WIDth="51" Text="4530" GrID.Column="1" margin="5,0" HorizontalAlignment="left"/><              TextBlock  x:name="textBlock4" Text="消息记录:" Height="23" GrID.Column="1" margin="5,0" Foreground="#FFE7D4E3" FontWeight="Bold"/> <              ListBox  x:name="ListBox1" GrID.Column="1" margin="5,0" Height="150"/> <              TextBlock x:name="textBlock3" Text="发送信息内容" Height="16" GrID.Column="1" d:LayoutOverrIDes="WIDth" margin="5,0" Foreground="#FFE7D4E3" FontWeight="Bold"/> <              TextBox x:name="MessageTextBox" GrID.Column="1" Height="50" margin="5,0"/> <              button Content="发送" Height="23" x:name="Sendbutton" GrID.Column="1" margin="5,0"/> <              button Content="清空" Height="23" x:name="Clearbutton" GrID.Column="1" margin="5,0"/> </          StackPanel></      GrID></  UserControl>

最后效果示意图:

服务器端:

Silverlight客户端:

后续工作中将结合地图来实现模拟实时位置的显示功能。。。。

 

 

(版权所有,转载请标明出处)

总结

以上是内存溢出为你收集整理的Silverlight Socket通信学习笔记全部内容,希望文章能够帮你解决Silverlight Socket通信学习笔记所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1021684.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存