博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Windows Phone开发(46):与Socket有个约会
阅读量:6434 次
发布时间:2019-06-23

本文共 11178 字,大约阅读时间需要 37 分钟。

原文:

不知道大家有没有“谈Socket色变”的经历?就像我一位朋友所说的,Socket这家伙啊,不得已而用之。哈,Socket真的那么恐怖吗?

其实这话一点也不假,Socket有时候真的不太好操控,也不好维护,但不管怎么样,我们还是要面对它的,没准Socket是一位大美女哦。

关于Socket的前世今生就不用我详述了,关于她的历史,已经不少人仁志士为她立传写著了,像我们国内的百度百科、互动百科等;全球著名的如维基百科之属。而且,能加入WP开发的学习行列的,我想各位对.NET的其它技术肯定是有一定基础的。我也相信,各位同仁过去一定也写过与Socket打交道的程序。那么,WP中的Socket又将如何呢?

前提公布答案吧,在WP中使用Socket跟你在其它桌面应用项目如WinForm,WPF等中是一样的,而且说白了,WP中的Socket只不过是从Silverlight框架中继承过来的。

.NET的一大优势就是集成性和统一性都好,这不,你看,无论你是编写桌面应用程序,还是WP上的应用程序,你会发现,你的学习成本不高,很多东西都是一样的,而且是相通的。显然这也是Win8和WP8的应用程序可以整合的原因吧。

在WP中使用Socket要注意以下几点:

1、WP客户端应用程序一般不被视为服务器端,因为不能进行绑定本地终结点和监听连接。但是,收发数据是没问题D。

2、在WP中的Socket操作(连接、接收以及发送)都是异步进行的。如果希望UI线程和后前线程进行同步,不妨使用System.Threading.ManualResetEvent类,这个东西不好讲述,也不好理解。这样吧,我举一个例子。

有一天,NC和脑残因为一件小事闹冲突,闹来闹去还是不能解决,怎么办呢?于是,NC和脑残决定来一场比试。两人约定以跑步方式比试,谁跑得快谁就是胜利者。然而,NC这个人一向比较自负,他相信脑残绝对跑不过他。这样,NC就修改了比赛规则:

NC让脑残先跑5秒,然后他才开始。

假设NC是主线程,脑残是后台线程,现在的情况是:主线程先等待一会儿,让后台线程先执行;后台线程执行5秒后向主线程发出信号,主线程收到信号后再继续往下执行。按照故事里的情节:NC先让脑残跑5秒钟,他自己就在起跑线上等待,脑残跑了5秒后向NC发出信号,NC看到信号后就开始跑。

下面介绍一个类——SocketAsyncEventArgs。

这个类作为启动异步操作时传递的参数,它可以包含如接收数据的缓冲区、远程主机、用户自定义对象等内容,这个类并不复杂,打开“对象浏览器”看看就一目了然了。

要设置用于异步接收数据的缓冲区,应调用SetBuffer方法。

好,理论就扯到这儿,其实也没有什么新的知识点,我只是简单提一下罢了。

按照惯例,大家都会猜到,理论过后要干什么了,是的,付诸实践。

 

在很多情况下,关于Socket的例子,都会做一个聊天程序的,不过,聊天程序要求服务器端和客户都具有发送和接收数据的功能,这样会增加实例的难度和代码长度,不方便入门者阅读。所以,想了一下,今天咱们不玩聊天的,今天咱们玩遥控飞机,如何?

程序代码较长,也不便于逐一来讲解,这样吧,为了保持代码的可读性,我会把完整的代码都贴出来,在代码中我会适当地加上注释。

先说一下原理,利用Socket进行通讯这不用说了,那是肯定的。功能是通过WP手机客户端应用程序来控制PC端播放、暂停和停止动画,而动画嘛,也不弄那么复杂了,就弄个矩形从左边移到右边的动画吧。

 

第一部分  服务器端

既然要播放动画,少不了要用WPF了,而且,也方便贴界面布局的代码。

1、新建WPF应用程序项目。

2、打开MainWindow.xaml文件(默认新建项目后自动打开),输入以下XAML代码。

3、打开MainWindow.xaml.cs文件,完成后台代码逻辑。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Navigation;using System.Windows.Shapes;using System.Windows.Media.Animation;using System.IO;using System.Net;using System.Net.Sockets;namespace MYServer{    ///     /// MainWindow.xaml 的交互逻辑    ///     public partial class MainWindow : Window    {        Storyboard std = null; //演示图板        public MainWindow()        {            InitializeComponent();            // 从资源中把Key为std的Storyboard读出来            std = this.Resources["std"] as Storyboard;            // 声明用于监听连接请求的Socket            Socket Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);            IPEndPoint local = new IPEndPoint(IPAddress.Any, 1377); //监听所有网络接口上的地址            Server.Bind(local);// 绑定本地终结点            Server.Listen(100);// 侦听连接请求            // 开始异步接受传入的连接请求            Server.BeginAccept(new AsyncCallback(this.AcceptSocketCallback), Server);        }        ///         /// 接受传入的Socket的回调        ///         private void AcceptSocketCallback(IAsyncResult ia)        {            Socket _socket = ia.AsyncState as Socket;            Socket accptSocket = _socket.EndAccept(ia);            try            {                IPEndPoint remote = (IPEndPoint)accptSocket.RemoteEndPoint;                // 显示客户端的IP                Dispatcher.BeginInvoke(new Action
(this.SetIPForText), remote.Address.ToString()); StateObject so = new StateObject(); so.theSocket = accptSocket; // 开始异步接收消息 accptSocket.BeginReceive(so.Buffer, 0, so.Buffer.Length, SocketFlags.None, new AsyncCallback(this.ReceiveCallback), so); } catch { } // 继续接受连接请求 _socket.BeginAccept(new AsyncCallback(this.AcceptSocketCallback), _socket); } ///
/// 接收消息的回调 /// private void ReceiveCallback(IAsyncResult ia) { StateObject _so = ia.AsyncState as StateObject; Socket _socket = _so.theSocket; try { int n = _socket.EndReceive(ia);//n就是接收到的字节数 string msg = Encoding.UTF8.GetString(_so.Buffer, 0, n); // 判断客户端发送了啥命令 switch (msg) { case "play": Dispatcher.BeginInvoke(new Action(this.Play), null); break; case "pause": Dispatcher.BeginInvoke(new Action(this.Pause), null); break; case "stop": Dispatcher.BeginInvoke(new Action(this.Stop), null); break; default: break; } } catch { } _so = new StateObject(); _so.theSocket = _socket; // 继续接收消息 _socket.BeginReceive(_so.Buffer, 0, _so.Buffer.Length, SocketFlags.None, new AsyncCallback(this.ReceiveCallback), _so); } ///
/// 显示客户端的IP /// private void SetIPForText(string ip) { this.txtDisplay.Text = "客户端IP:" + ip; } #region 控制动画的方法 private void Play() { std.Begin(); } private void Pause() { std.Pause(); } private void Stop() { std.Stop(); } #endregion } ///
/// 用于异步Socket操作传递的状态对象 /// public class StateObject { private const int BUFFER_SIZE = 512; public byte[] Buffer { get; set; } public Socket theSocket { get; set; } ///
/// 构造函数 /// public StateObject() { this.Buffer = new byte[BUFFER_SIZE]; } }}

 

 

第二部分  WP客户端

1、新建Windows Phone应用程序项目。

2、打开MainPage.xaml文件,参考下面的XAML代码。

3、打开MainPage.xaml.cs,输入以下代码。

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 Microsoft.Phone.Controls;using System.Net.Sockets;using System.IO;using System.Threading;namespace WPClient{    public partial class MainPage : PhoneApplicationPage    {        Socket mySocket = null;        ManualResetEvent MyEvent = null;        // 构造函数        public MainPage()        {            InitializeComponent();        }        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)        {            base.OnNavigatedTo(e);            if (mySocket == null)            {                mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);            }            if (MyEvent == null)            {                MyEvent = new ManualResetEvent(false);            }        }        protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)        {            if (mySocket != null)            {                mySocket.Shutdown(SocketShutdown.Both);                mySocket.Close();            }            base.OnNavigatedFrom(e);        }        private void onConnect(object sender, RoutedEventArgs e)        {            if (mySocket != null)            {                SocketAsyncEventArgs connArg = new SocketAsyncEventArgs();                // 要连接的远程服务器                connArg.RemoteEndPoint = new DnsEndPoint(this.txtServerIP.Text, 1377);                // 操作完成后的回调                connArg.Completed += (sendObj, arg) =>                {                    if (arg.SocketError == SocketError.Success) //连接成功                    {                        Dispatcher.BeginInvoke(() => txtbInfo.Text = "连接成功。");                    }                    else                    {                        Dispatcher.BeginInvoke(() =>                        {                            txtbInfo.Text = "连接失败,错误:" + arg.SocketError.ToString();                        });                    }                    // 向调用线程报告操作结束                    MyEvent.Set();                };                // 重置线程等待事件                MyEvent.Reset();                txtbInfo.Text = "正在连接,请等候……";                // 开始异连接                mySocket.ConnectAsync(connArg);                // 等待连接完成                MyEvent.WaitOne(6000);            }        }        private void onPause(object sender, RoutedEventArgs e)        {            SendCommand("pause");        }        private void onStop(object sender, RoutedEventArgs e)        {            SendCommand("stop");        }        private void onPlay(object sender, RoutedEventArgs e)        {            SendCommand("play");        }        private void SendCommand(string txt)        {            if (mySocket != null && mySocket.Connected)            {                SocketAsyncEventArgs sendArg = new SocketAsyncEventArgs();                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(txt);                sendArg.SetBuffer(buffer, 0, buffer.Length);                // 发送完成后的回调                sendArg.Completed += (objSender, mArg) =>                    {                        // 如果操作成功                        if (mArg.SocketError == SocketError.Success)                        {                            Dispatcher.BeginInvoke(() => txtbInfo.Text = "发送成功。");                        }                        else                        {                            Dispatcher.BeginInvoke(() =>                                {                                    this.txtbInfo.Text = "发送失败,错误:" + mArg.SocketError.ToString();                                });                        }                        // 报告异步操作结束                        MyEvent.Set();                    };                // 重置信号                MyEvent.Reset();                txtbInfo.Text = "正在发送,请等候……";                // 异步发送                mySocket.SendAsync(sendArg);                // 等待操作完成                MyEvent.WaitOne(6000);            }        }    }}

 

先运行服务器端,再在WP模拟器或真实手机上运行客户端。

在手机客户端中,输入IP地址,点“连接”,连接成功后,就可以发送指令了。

 

 好的,就到这儿吧,示例的源码我会上专到“资源”中,有需要的话,大家可以按标题下载。

 

 

转载地址:http://cvqga.baihongyu.com/

你可能感兴趣的文章
java一些常用并发工具示例
查看>>
45. Jump Game II
查看>>
c++ 类内static成员初始化
查看>>
python-ConfigParser模块【读写配置文件】
查看>>
更改printk打印级别【转】
查看>>
2.2 dubbo-spi源码解析
查看>>
hadoop之 YARN配置参数剖析—RM与NM相关参数
查看>>
软件开发中的几种数据交换协议
查看>>
MySQL多个相同结构的表查询并把结果合并放在一起的语句(union all)
查看>>
Xilinx下载方式(具体可以参考配置MCS文件时右下角help调出的doc)
查看>>
FINDSTR 命令使用详解
查看>>
Linux下scp的用法
查看>>
Git远程库版本回滚
查看>>
前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器
查看>>
云中的机器学习:FPGA 上的深度神经网络
查看>>
咬文嚼字:结构
查看>>
Kafka#4:存储设计 分布式设计 源码分析
查看>>
js实现置顶
查看>>
.NET分布式缓存Redis从入门到实战
查看>>
DPDK 全面分析
查看>>