使用Socket通信实现Silverlight客户端实时数据的获取(模拟GPS数据,地图实时位置)
在上一篇中说到了Silverlight下的Socket通信,在最后的时候说到本篇将会结合地图。下面就来看看本文实现的功能:
Silverlight 与服务器利用Socket通讯,实时从服务器获取数据(本文中的数据是地理坐标),由于没有GPS,所以本文在服务器写了一个构造新坐标的函数(本文是一个三角函数),然后利用Timer组件,实时调用,得到新的坐标,并将新的坐标发送给客户端,客户端接收到发回的新的坐标,并在地图相应的位置进行标识。最后在地图上我们就会看到一个自动绘制的三角函数曲线。
关于本文的一点说明:
1.由于时间和篇幅的关系,也由于本人能力有限,所以程序还存在很多bug,不够完善,也许你运行的时候还会抛异常,本文关注的是关键功能的实现,所以希望高手勿喷,如果您有更好的方法和建议欢迎留言分享。
2.作者没有GPS设置,相信大多数也是一样,所以无法实际的模拟从GPS获取数据,在地图上展示,因此本文模拟在服务器动态实时的生成坐标数据,并实时发送给客户端。不过如果您有GPS设备,实际上实现的过程是一样。
3.本文的坐标数据是自己写的一个三角函数,所以最后在地图上实时绘制的运动轨迹也是一个三角函数,当然也可以换成其他任意的轨迹,只要可以写出其坐标生成函数即可。
4.本文的具体过程是客户端向服务器发送一个起始的坐标,当然也可以是其他的信息,只不过便于绘制和理解,所以用了一个坐标,服务器接收该坐标,并基于该坐标生成新的坐标数据。不过在实际的GPS中,只需要客户端发送位置请求,服务器将真实的GPS坐标数据发送给客户端即可。
5.本文的服务器端部分代码来自于该博主的博文:
http://www.cnblogs.com/webabcd/archive/2008/12/22/1359551.html
在此感谢webabcd(王磊 MVP)的分享。
下面就来看看具体实现的过程。
一.服务器端
在上一篇中说到了与服务器通信,大致上的过程是客户端发送一个信息,服务器接收客户端信息,服务器回复一条信息,客户端接收服务器信息。但在本文中,稍微有些不一样。
在本文中,客户端发送位置请求(本文客户端发送一个用于构造新坐标的起始坐标点),然后服务器基于接收的起始坐标,实时的生成新的坐标数据,并不断的往客户端发送,客户端不断接受服务器发送来的新数据,并在地图上标示。所以这里不像之前客户端请求一次,服务器则回复一条信息。
下面给出具体的代码I(可以参看上面给出链接的博文):
服务器端界面如下:
具体过程:
1.1 启动策略文件服务
#region Start The Policy Server 验证策略文件 PolicySocketServer StartPolicyServer = new PolicySocketServer(); Thread th = new Thread(new ThreadStart(StartPolicyServer.StartSocketServer)); th.IsBackground = true; th.Start(); #endregion
PolicySocketServer 类在上一篇文章中给出:
http://www.cnblogs.com/potential/archive/2013/01/23/2873035.html
1.2 启动服务器端Socket服务,监听端口,连接Socket。
1.2.1 声明类级别的变量
//客户端传入的起始坐标 private double startx = 0; private double starty = 0; //服务器端生成的新坐标 private double X; private double Y; //判断是否成功接收服务器发来的新的坐标 bool receivedCoor = false; //够找新坐标时的步长 private double step = 0;
1.2.2启动Socket服务,开始连接
private void StartupSocketServer() { //定时器,每0.3秒运行一次指定的方法 //这里可自己手动修改刷新数据的时间 _timer = new System.Timers.Timer(); _timer.Interval = 300; _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed); _timer.Start(); //初始化Socket _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //创建终结点,获取当前主机IP IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName()); IPEndPoint localEndPoint = new IPEndPoint(ipHost.AddressList[3], 4530); //Win7 启动了IPV6地址,所以是3,如果为XP系统可换成0,1再试试 _syncContext.Post(ChangeIPText, ipHost.AddressList[3].ToString()); //绑定端口 _listener.Bind(localEndPoint); _listener.Listen(100); while (true) { //重置ManualResetEvent,由线程来控制ManualResetEvent _connectDone.Reset(); _listener.BeginAccept(new AsyncCallback(OnClientConnect), null); _connectDone.WaitOne(); } }
private void OnClientConnect(IAsyncResult result) { _connectDone.Set(); ClientSocketPacket client = new ClientSocketPacket(); client.Socket = _listener.EndAccept(result); _clientList.Add(client); _syncContext.Post(ResultCallback, "客户端已经连接"); try { client.Socket.BeginReceive(client.Buffer, 0, client.Buffer.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), client); } catch (SocketException ex) { HandleException(client, ex); } }
1.3 接收数据
private void OnDataReceived(IAsyncResult result) { ClientSocketPacket client = result.AsyncState as ClientSocketPacket; int count = 0; try { if (client.Socket.Connected) count = client.Socket.EndReceive(result); } catch (SocketException ex) { HandleException(client,ex); } foreach (byte b in client.Buffer.Take(count)) { if (b == 0) continue; client.RececivedByte.Add(b); } string receivedString = UTF8Encoding.UTF8.GetString(client.Buffer, 0, count); if (client.Socket.Connected && client.Socket.Available == 0 && receivedString.Contains(_endMarker)) { string content = UTF8Encoding.UTF8.GetString(client.RececivedByte.ToArray()); content = content.Replace(_endMarker, ""); client.RececivedByte.Clear(); SendData("服务器端已经成功接收数据!"); _syncContext.Post(ResultCallback, "服务器在" + DateTime.Now.ToShortTimeString() + "接收数据:" + content); } //对接受的数据进行分析 //便于简单,客户端发送的坐标字符串格式是"x|y" //所以这里只是简单的判断是否有‘|’标识符 if (receivedString.Contains("|")) { string[] coordinates = receivedString.Split('|'); startx = Convert.ToDouble(coordinates[0]); starty = Convert.ToDouble(coordinates[1]); _syncContext.Post(ChangeReceivedText, receivedString); step = 0; receivedCoor = true; } try { // 继续开始接收客户端传入的数据 if (client.Socket.Connected) client.Socket.BeginReceive(client.Buffer, 0, client.Buffer.Length, 0, new AsyncCallback(OnDataReceived), client); } catch (SocketException ex) { HandleException(client, ex); } }
1.5 发送数据等
private void SendData(string data) { byte[] byteData = UTF8Encoding.UTF8.GetBytes(data); for (int i = 0; i < _clientList.Count;i++ ) { if (_clientList[i].Socket.Connected) { _clientList[i].Socket.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnDataSend), _clientList[i]); _syncContext.Post(ResultCallback, "服务器在" + DateTime.Now.ToShortTimeString() + "发送数据:" + data); } else { _clientList[i].Socket.Close(); _clientList.Remove(_clientList[i]); } } }
1.6 生成新坐标的方法,本文利用的只是一个简单的Sin三角函数,读者可构造自己的函数。
private void newCoordinate(out double latitude, out double longitude, ref double step) { latitude = startx + 30 * step; longitude = starty + 100 * Math.Sin(step); step = step + 0.1; }
1.7 Timer定时器的触发函数,定时向调用构造新坐标的方法,构造新的坐标,并发送数据的到客户端
private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { //如果服务器成功接收客户端传入的坐标,则向服务器发送数据 if (receivedCoor == true) { newCoordinate(out X, out Y, ref step); string lat = startx.ToString("#0.00"); string lon = starty.ToString("#0.00"); //将新的坐标发送给客户端 SendData(string.Format("{0}|{1}", X, Y)); } }
1.8 其他相关函数,用于更改UI
private void ResultCallback(object result) { // 输出相关信息 listBox1.Items.Add(result); } private void ChangeIPText(object str) { HostIPTextBox.Text = str.ToString(); } private void ChangeReceivedText(object str) { ReceivedTextBox.Text = str.ToString(); }
1.9 开启Socket服务Button事件,及清除消息列表
private void StartButton_Click(object sender, EventArgs e) { // 启动后台线程去运行 Socket 服务 Thread thread = new Thread(new ThreadStart(StartupSocketServer)); thread.IsBackground = true; thread.Start(); } private void ClearButton_Click(object sender, EventArgs e) { listBox1.Items.Clear(); }
Main.cs
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using System.Threading; 10 using System.Net.Sockets; 11 using System.Net; 12 using System.IO; 13 14 namespace WindowsServer 15 { 16 public partial class Form1 : Form 17 { 18 SynchronizationContext _syncContext; 19 System.Timers.Timer _timer; 20 private string _endMarker = "^"; 21 22 private Socket _listener; 23 24 private ManualResetEvent _connectDone = new ManualResetEvent(false); 25 private List<ClientSocketPacket> _clientList = new List<ClientSocketPacket>(); 26 27 //客户端传入的起始坐标 28 private double startx = 0; 29 private double starty = 0; 30 //服务器端生成的新坐标 31 private double X; 32 private double Y; 33 //判断是否成功接收服务器发来的新的坐标 34 bool receivedCoor = false; 35 //够找新坐标时的步长 36 private double step = 0; 37 38 public Form1() 39 { 40 InitializeComponent(); 41 #region Start The Policy Server 验证策略文件 42 PolicySocketServer StartPolicyServer = new PolicySocketServer(); 43 Thread th = new Thread(new ThreadStart(StartPolicyServer.StartSocketServer)); 44 th.IsBackground = true; 45 th.Start(); 46 #endregion 47 48 //UI线程 49 _syncContext = SynchronizationContext.Current; 50 //启动线程运行Socket服务 51 52 } 53 54 private void StartupSocketServer() 55 { 56 //定时器,每0.3秒运行一次指定的方法 57 //这里可自己手动修改刷新数据的时间 58 _timer = new System.Timers.Timer(); 59 _timer.Interval = 300; 60 _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed); 61 _timer.Start(); 62 63 //初始化Socket 64 _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 65 //创建终结点,获取当前主机IP 66 IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName()); 67 IPEndPoint localEndPoint = new IPEndPoint(ipHost.AddressList[3], 4530); 68 //Win7 启动了IPV6地址,所以是3,如果为XP系统可换成0,1再试试 69 _syncContext.Post(ChangeIPText, ipHost.AddressList[3].ToString()); 70 //绑定端口 71 _listener.Bind(localEndPoint); 72 _listener.Listen(100); 73 74 while (true) 75 { 76 //重置ManualResetEvent,由线程来控制ManualResetEvent 77 _connectDone.Reset(); 78 79 _listener.BeginAccept(new AsyncCallback(OnClientConnect), null); 80 81 _connectDone.WaitOne(); 82 } 83 } 84 85 private void OnClientConnect(IAsyncResult result) 86 { 87 _connectDone.Set(); 88 ClientSocketPacket client = new ClientSocketPacket(); 89 client.Socket = _listener.EndAccept(result); 90 _clientList.Add(client); 91 _syncContext.Post(ResultCallback, "客户端已经连接"); 92 93 try 94 { 95 client.Socket.BeginReceive(client.Buffer, 0, client.Buffer.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), client); 96 } 97 catch (SocketException ex) 98 { 99 HandleException(client, ex); 100 } 101 } 102 103 private void OnDataReceived(IAsyncResult result) 104 { 105 ClientSocketPacket client = result.AsyncState as ClientSocketPacket; 106 int count = 0; 107 try 108 { 109 if (client.Socket.Connected) 110 count = client.Socket.EndReceive(result); 111 } 112 catch (SocketException ex) 113 { 114 HandleException(client,ex); 115 } 116 117 foreach (byte b in client.Buffer.Take(count)) 118 { 119 if (b == 0) 120 continue; 121 client.RececivedByte.Add(b); 122 } 123 124 string receivedString = UTF8Encoding.UTF8.GetString(client.Buffer, 0, count); 125 if (client.Socket.Connected && client.Socket.Available == 0 && receivedString.Contains(_endMarker)) 126 { 127 string content = UTF8Encoding.UTF8.GetString(client.RececivedByte.ToArray()); 128 content = content.Replace(_endMarker, ""); 129 client.RececivedByte.Clear(); 130 SendData("服务器端已经成功接收数据!"); 131 _syncContext.Post(ResultCallback, "服务器在" + DateTime.Now.ToShortTimeString() + "接收数据:" + content); 132 } 133 //对接受的数据进行分析 134 //便于简单,客户端发送的坐标字符串格式是"x|y" 135 //所以这里只是简单的判断是否有‘|’标识符 136 if (receivedString.Contains("|")) 137 { 138 string[] coordinates = receivedString.Split('|'); 139 startx = Convert.ToDouble(coordinates[0]); 140 starty = Convert.ToDouble(coordinates[1]); 141 _syncContext.Post(ChangeReceivedText, receivedString); 142 step = 0; 143 receivedCoor = true; 144 } 145 146 try 147 { 148 // 继续开始接收客户端传入的数据 149 if (client.Socket.Connected) 150 client.Socket.BeginReceive(client.Buffer, 0, client.Buffer.Length, 0, new AsyncCallback(OnDataReceived), client); 151 } 152 catch (SocketException ex) 153 { 154 HandleException(client, ex); 155 } 156 } 157 158 private void SendData(string data) 159 { 160 byte[] byteData = UTF8Encoding.UTF8.GetBytes(data); 161 for (int i = 0; i < _clientList.Count;i++ ) 162 { 163 164 if (_clientList[i].Socket.Connected) 165 { 166 _clientList[i].Socket.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnDataSend), _clientList[i]); 167 _syncContext.Post(ResultCallback, "服务器在" + DateTime.Now.ToShortTimeString() + "发送数据:" + data); 168 } 169 else 170 { 171 _clientList[i].Socket.Close(); 172 _clientList.Remove(_clientList[i]); 173 } 174 } 175 } 176 177 private void OnDataSend(IAsyncResult result) 178 { 179 ClientSocketPacket client = result.AsyncState as ClientSocketPacket; 180 try 181 { 182 if (client.Socket.Connected) 183 client.Socket.EndSend(result); 184 } 185 catch (SocketException ex) 186 { 187 HandleException(client, ex); 188 } 189 } 190 191 private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 192 { 193 //如果服务器成功接收客户端传入的坐标 194 if (receivedCoor == true) 195 { 196 newCoordinate(out X, out Y, ref step); 197 string lat = startx.ToString("#0.00"); 198 string lon = starty.ToString("#0.00"); 199 //将新的坐标发送给客户端 200 SendData(string.Format("{0}|{1}", X, Y)); 201 } 202 } 203 204 private void newCoordinate(out double latitude, out double longitude, ref double step) 205 { 206 latitude = startx + 30 * step; 207 208 longitude = starty + 100 * Math.Sin(step); 209 210 step = step + 0.1; 211 } 212 213 private void HandleException(ClientSocketPacket client, SocketException ex) 214 { 215 if (client.Socket == null) 216 return; 217 // 在服务端记录异常信息,关闭导致异常的 Socket,并将其清除出客户端 Socket 列表 218 _syncContext.Post(ResultCallback, client.Socket.RemoteEndPoint.ToString() + " - " + ex.Message); 219 client.Socket.Close(); 220 _clientList.Remove(client); 221 } 222 223 private void ResultCallback(object result) 224 { 225 // 输出相关信息 226 listBox1.Items.Add(result); 227 } 228 229 private void ChangeIPText(object str) 230 { 231 HostIPTextBox.Text = str.ToString(); 232 } 233 private void ChangeReceivedText(object str) 234 { 235 ReceivedTextBox.Text = str.ToString(); 236 } 237 private void StartButton_Click(object sender, EventArgs e) 238 { 239 // 启动后台线程去运行 Socket 服务 240 Thread thread = new Thread(new ThreadStart(StartupSocketServer)); 241 thread.IsBackground = true; 242 thread.Start(); 243 } 244 245 private void StopButton_Click(object sender, EventArgs e) 246 { 247 listBox1.Items.Clear(); 248 } 249 } 250 }
二、Silverlight客户端
UI界面如下:
客户端实现的过程和上一篇文章差不多,代码几乎没有变化,只不过是连续的想服务器获取数据,代码如下:
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("Socket连接已断开!")); } return; } //如果连接上,则发送数据 if (e.LastOperation == SocketAsyncOperation.Connect) { byte[] userbytes = (byte[])e.UserToken; e.SetBuffer(userbytes, 0, 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, 0, userbytes.Length); socket.ReceiveAsync(e); }//接收服务器数据 else if (e.LastOperation == SocketAsyncOperation.Receive) { string RecevieStr = Encoding.UTF8.GetString(e.Buffer, 0, e.Buffer.Length).Replace("\0", ""); Dispatcher.BeginInvoke(() => { listBox1.Items.Add("服务器在" + DateTime.Now.ToShortTimeString() + ",回复消息:" + RecevieStr); }); //分析服务器发送回来的坐标数据,数据格式“x|y” if (RecevieStr.Contains("|")) { string[] coor = RecevieStr.Split('|'); //构造新的坐标点 MapPoint mp1 = new MapPoint(Convert.ToDouble(x), Convert.ToDouble(y)); x = coor[0]; y = coor[1]; MapPoint mp2 = new MapPoint(Convert.ToDouble(x), Convert.ToDouble(y)); //在地图中绘制点和轨迹 Dispatcher.BeginInvoke(() => { CreatPoint(mp2); }); Dispatcher.BeginInvoke(() => { CreatLine(mp1, mp2);}); } //继续向服务器接收数据,注意不要关闭Socket连接 socket.ReceiveAsync(e); } }
在地图上添加点和线的方法
private void CreatPoint(MapPoint mp) { Graphic g = new Graphic() { Symbol = new SimpleMarkerSymbol() { Size = 18, Color = new SolidColorBrush(Colors.Blue), Style = SimpleMarkerSymbol.SimpleMarkerStyle.Circle }, Geometry = mp }; graphiclayer.Graphics.Clear(); graphiclayer.Graphics.Add(g); } private void CreatLine(MapPoint mp1,MapPoint mp2) { ESRI.ArcGIS.Client.Geometry.Polyline pl = new ESRI.ArcGIS.Client.Geometry.Polyline(); ESRI.ArcGIS.Client.Geometry.PointCollection pc = new ESRI.ArcGIS.Client.Geometry.PointCollection(); pc.Add(mp1); pc.Add(mp2); pl.Paths.Add(pc); Graphic g = new Graphic() { Symbol=LayoutRoot.Resources["LineSymbol"] as SimpleLineSymbol, Geometry = pl }; routeLayer.Graphics.Add(g); }
本文通过双击地图获得一个起始点坐标,并将该坐标发送给服务器,示例代码:
private void MyMap_MouseClick(object sender, ESRI.ArcGIS.Client.Map.MouseEventArgs e) { MapPoint mp = e.MapPoint; x = mp.X.ToString ("#0.00"); y = mp.Y.ToString ("#0.00"); Graphic g = new Graphic() { Symbol = new SimpleMarkerSymbol() { Size=9, Color=new SolidColorBrush(Colors.Blue), Style=SimpleMarkerSymbol.SimpleMarkerStyle.Circle }, Geometry=mp }; graphiclayer.Graphics.Add(g); MessageTextBox.Text = x + "|" + y; }
关于其他部分的代码,例如声明图层,情况列表再次不再强调,具体请看下面代码:
MainPage.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Net; 5 using System.Windows; 6 using System.Windows.Controls; 7 using System.Windows.Documents; 8 using System.Windows.Input; 9 using System.Windows.Media; 10 using System.Windows.Media.Animation; 11 using System.Windows.Shapes; 12 using System.Net.Sockets; 13 using System.Text; 14 using ESRI.ArcGIS.Client; 15 using ESRI.ArcGIS.Client.Geometry; 16 using ESRI.ArcGIS.Client.Symbols; 17 using ESRI.ArcGIS.Client.Tasks; 18 namespace SilverlightSocket 19 { 20 public partial class MainPage : UserControl 21 { 22 private Socket socket; 23 private string x, y; 24 GraphicsLayer graphiclayer; 25 GraphicsLayer routeLayer; 26 public MainPage() 27 { 28 InitializeComponent(); 29 SendButton.Click += new RoutedEventHandler(SendButton_Click); 30 ClearButton.Click += ClearButton_Click; 31 MyMap.MouseClick+=MyMap_MouseClick; 32 graphiclayer = MyMap.Layers["GraphicLayer"] as GraphicsLayer; 33 routeLayer = MyMap.Layers["routeLayer"] as GraphicsLayer; 34 } 35 36 private void MyMap_MouseClick(object sender, ESRI.ArcGIS.Client.Map.MouseEventArgs e) 37 { 38 MapPoint mp = e.MapPoint; 39 x = mp.X.ToString ("#0.00"); 40 y = mp.Y.ToString ("#0.00"); 41 Graphic g = new Graphic() 42 { 43 Symbol = new SimpleMarkerSymbol() 44 { 45 Size=9, 46 Color=new SolidColorBrush(Colors.Blue), 47 Style=SimpleMarkerSymbol.SimpleMarkerStyle.Circle 48 }, 49 Geometry=mp 50 }; 51 graphiclayer.Graphics.Add(g); 52 MessageTextBox.Text = x + "|" + y; 53 } 54 55 void ClearButton_Click(object sender, RoutedEventArgs e) 56 { 57 listBox1.Items.Clear(); 58 } 59 60 private void SendButton_Click(object sender, RoutedEventArgs e) 61 { 62 if(string.IsNullOrEmpty(IPTextBox.Text)||string.IsNullOrEmpty(PortTextBox.Text)) 63 { 64 MessageBox.Show ("请输入主机IP地址和端口号!"); 65 return; 66 } 67 //ip地址 68 string host=IPTextBox.Text.Trim(); 69 //端口号 70 int port=Convert.ToInt32(PortTextBox.Text.Trim()); 71 //建立终结点对象 72 DnsEndPoint hostEntry=new DnsEndPoint(host,port); 73 //创建一个Socket对象 74 socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); 75 //创建Socket异步事件参数 76 SocketAsyncEventArgs socketEventArg=new SocketAsyncEventArgs (); 77 //将消息转化为发送的byte[]格式 78 byte[]buffer=Encoding.UTF8.GetBytes(MessageTextBox.Text); 79 //注册Socket完成事件 80 socketEventArg.Completed+=new EventHandler<SocketAsyncEventArgs>(socketEventArg_Completed); 81 //设置Socket异步事件远程终结点 82 socketEventArg.RemoteEndPoint=hostEntry; 83 //将定义好的Socket对象赋值给Socket异步事件参数的运行实例属性 84 socketEventArg.UserToken = buffer; 85 //socketEventArg.UserToken = socket; 86 try 87 { 88 socket.ConnectAsync(socketEventArg); 89 } 90 catch(SocketException ex) 91 { 92 throw new SocketException((int)ex.ErrorCode); 93 } 94 } 95 96 private void socketEventArg_Completed(object sender, SocketAsyncEventArgs e) 97 { 98 //检查是否发送出错 99 if (e.SocketError != SocketError.Success) 100 { 101 if (e.SocketError == SocketError.ConnectionAborted) 102 { 103 Dispatcher.BeginInvoke(() => MessageBox.Show("连接超时....请重试!")); 104 } 105 else if (e.SocketError == SocketError.ConnectionRefused) 106 { 107 Dispatcher.BeginInvoke(() => MessageBox.Show("无法连接到服务器端:"+e.SocketError)); 108 }else 109 { 110 Dispatcher.BeginInvoke(() => MessageBox.Show("Socket连接已断开!")); 111 } 112 return; 113 } 114 //如果连接上,则发送数据 115 if (e.LastOperation == SocketAsyncOperation.Connect) 116 { 117 byte[] userbytes = (byte[])e.UserToken; 118 e.SetBuffer(userbytes, 0, userbytes.Length); 119 socket.SendAsync(e); 120 121 }//如果已发送数据,则开始接收服务器回复的消息 122 else if (e.LastOperation == SocketAsyncOperation.Send) 123 { 124 Dispatcher.BeginInvoke(() => 125 { 126 listBox1.Items.Add("客户端在" + DateTime.Now.ToShortTimeString() + ",发送消息:" + MessageTextBox.Text); 127 }); 128 byte[] userbytes = new byte[1024]; 129 e.SetBuffer(userbytes, 0, userbytes.Length); 130 socket.ReceiveAsync(e); 131 }//接收服务器数据 132 else if (e.LastOperation == SocketAsyncOperation.Receive) 133 { 134 string RecevieStr = Encoding.UTF8.GetString(e.Buffer, 0, e.Buffer.Length).Replace("\0", ""); 135 Dispatcher.BeginInvoke(() => 136 { 137 listBox1.Items.Add("服务器在" + DateTime.Now.ToShortTimeString() + ",回复消息:" + RecevieStr); 138 }); 139 if (RecevieStr.Contains("|")) 140 { 141 string[] coor = RecevieStr.Split('|'); 142 MapPoint mp1 = new MapPoint(Convert.ToDouble(x), Convert.ToDouble(y)); 143 x = coor[0]; 144 y = coor[1]; 145 MapPoint mp2 = new MapPoint(Convert.ToDouble(x), Convert.ToDouble(y)); 146 Dispatcher.BeginInvoke(() => { CreatPoint(mp2); }); 147 Dispatcher.BeginInvoke(() => { CreatLine(mp1, mp2);}); 148 } 149 socket.ReceiveAsync(e); 150 } 151 } 152 153 private void CreatPoint(double x,double y) 154 { 155 MapPoint mp = new MapPoint(x, y); 156 Graphic g = new Graphic() 157 { 158 Symbol = new SimpleMarkerSymbol() 159 { 160 Size = 18, 161 Color = new SolidColorBrush(Colors.Blue), 162 Style = SimpleMarkerSymbol.SimpleMarkerStyle.Circle 163 }, 164 Geometry = mp 165 }; 166 graphiclayer.Graphics.Clear(); 167 graphiclayer.Graphics.Add(g); 168 } 169 170 private void CreatPoint(MapPoint mp) 171 { 172 Graphic g = new Graphic() 173 { 174 Symbol = new SimpleMarkerSymbol() 175 { 176 Size = 18, 177 Color = new SolidColorBrush(Colors.Blue), 178 Style = SimpleMarkerSymbol.SimpleMarkerStyle.Circle 179 }, 180 Geometry = mp 181 }; 182 graphiclayer.Graphics.Clear(); 183 graphiclayer.Graphics.Add(g); 184 } 185 186 private void CreatLine(MapPoint mp1,MapPoint mp2) 187 { 188 ESRI.ArcGIS.Client.Geometry.Polyline pl = new ESRI.ArcGIS.Client.Geometry.Polyline(); 189 ESRI.ArcGIS.Client.Geometry.PointCollection pc = new ESRI.ArcGIS.Client.Geometry.PointCollection(); 190 pc.Add(mp1); 191 pc.Add(mp2); 192 pl.Paths.Add(pc); 193 Graphic g = new Graphic() 194 { 195 Symbol=LayoutRoot.Resources["LineSymbol"] as SimpleLineSymbol, 196 Geometry = pl 197 }; 198 routeLayer.Graphics.Add(g); 199 } 200 201 private void StopButton_Click_1(object sender, RoutedEventArgs e) 202 { 203 if (socket != null) 204 socket.Shutdown(SocketShutdown.Both); 205 socket.Close(); 206 } 207 } 208 }
MainPage.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"> <Grid x:Name="LayoutRoot" Background="White" Width="900"> <Grid.Resources> <esri:SimpleLineSymbol x:Key="LineSymbol" Color="Red" Style="Solid" Width="3"/> </Grid.Resources> <Grid.ColumnDefinitions> <ColumnDefinition Width="0.868*"/> <ColumnDefinition Width="200"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition/> </Grid.RowDefinitions> <esri:Map x:Name="MyMap" Background="White" WrapAround="True" Grid.ColumnSpan="2"> <esri:ArcGISTiledMapServiceLayer Url="http://www.arcgisonline.cn/ArcGIS/rest/services/ChinaOnlineStreetColor/MapServer"/> <esri:GraphicsLayer ID="routeLayer"/> <esri:GraphicsLayer ID="GraphicLayer"/> </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,0" Foreground="#FFE7D4E3" FontWeight="Bold" /> <TextBox x:Name="IPTextBox" Text="169.254.57.67" Grid.Column="1" d:LayoutOverrides="Width" Margin="5,5,0,0" HorizontalAlignment="Left"/> <TextBlock x:Name="textBlock2" Text="端口号" Grid.Column="1" Margin="5,5,0,0" Foreground="#FFE7D4E3" FontWeight="Bold" /> <TextBox x:Name="PortTextBox" Width="51" Text="4530" Grid.Column="1" Margin="5,5,0,0" HorizontalAlignment="Left"/> <TextBlock x:Name="textBlock4" Text="消息记录:" Height="23" Grid.Column="1" Margin="5,5,0,0" Foreground="#FFE7D4E3" FontWeight="Bold" /> <ListBox x:Name="listBox1" Grid.Column="1" Margin="5,5,0,0" Height="200" /> <TextBlock x:Name="textBlock3" Text="发送信息内容" Height="16" Grid.Column="1" d:LayoutOverrides="Width" Margin="5,5,0,0" Foreground="#FFE7D4E3" FontWeight="Bold" VerticalAlignment="Bottom" /> <TextBox x:Name="MessageTextBox" Grid.Column="1" Height="50" Margin="5,5,0,0" VerticalAlignment="Bottom" /> <Button Content="发送" Height="23" x:Name="SendButton" Grid.Column="1" Margin="5,5,0,0" VerticalAlignment="Bottom" /> <Button Content="清空" Height="23" x:Name="ClearButton" Grid.Column="1" Margin="5,5,0,0" VerticalAlignment="Bottom" /> <Button Content="停止" Height="23" x:Name="StopButton" Grid.Column="1" Margin="5,5,0,0" VerticalAlignment="Bottom" Click="StopButton_Click_1" /> </StackPanel> <esri:ScaleLine HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="30,0,0,20" Map="{Binding ElementName=MyMap}"/> </Grid> </UserControl>
最后的效果:
服务器端:
客户端:
由于是图片,所以无法预览动态绘制的效果,只能看图片了。
(版权所有,转载请标明出处)