欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Windows phone开发之支持的通信方式

程序员文章站 2023-01-23 11:53:54
1. http协议 主要是由webclient或httpwebrequest两个类提供,直接封装http协议访问web站点。最常用的通信方式。 2. wcf wcf作为ms大力的通信方案非常强大,但...
1. http协议
主要是由webclient或httpwebrequest两个类提供,直接封装http协议访问web站点。最常用的通信方式。
2. wcf
wcf作为ms大力的通信方案非常强大,但是到了wp7上就变成了太监,只支持简单的basichttpbinding而且还有非常多的限制。
3 socket
7.1sdk里新增的通信方式,支持tcp和udp但只能使用异步的socketasynceventargs事件方式,也有不少限制。
 
选择通信方式
因为同时需要考虑到服务器端的实现,在服务器端尽量精简,最好不要有什么iis之类大型依赖。
对应是服务器端实现方式如下:

 
http协议 httplistener
wcf wcf应用程序宿主
socket socket
 

由于我使用的是win7 httplistener和basichttpbinding在监听外网ip时都需要管理员身份验证,这点很不友好,我每次开程序都提示一下,不爽。所以决定使用socket。
 
socket协议选择
而socket分为tcp和udp,为了稳定选择了有重传功能和回复的tcp(其实udp也不是什么问题)。
tcp需要3次握手来维持链接,但是按照“偶尔连接”(occasionally connect)的设计准则,我不能让手机一直保持连接,而且断线检查也是个麻烦事。
所以决定采用http1.0类似的短链接方式,就是连上、发一条消息、然后断开的流程(暂时没有回复)
 
 
应用层消息报文设计
这个程序比较简单设计的报文也很简单,
因为内网传输不需要考虑身份验证,、完整性等,而且短链接不会遇到粘包和拆包之类的,真是太轻松了。
报文结构如下

 
length 长度 4字节int
action 动作 32字节utf8编码
context 内容 长度由length描述utf8编码
 
 

length表示context的长度,报文本身长度为length+4+32
action目前只有”tap”按键 一种
context表示按键的类型 有2种分类
一种是  keyboard 直接对应键盘的键名称
另一种是 media 媒体控制用 包括toggleplaypause(播放暂停)、forward(前进)、backward(后退)increasevolume(提高音量)等
表示方式是“media.toggleplaypause”

view code
namespace virtualkeyboard.contract
{
    public static class keymethods
    {
        public const string keyboardpackage = "keyboard";
        public const string mediapackage = "media";

        public static class keyboard
        {
            private const string keyboardpre = keyboardpackage + ".";

            /// <summary>
            /// enter
            /// </summary>
            public const string enter = keyboardpre + "enter";

            /// <summary>
            /// esc
            /// </summary>
            public const string esc = keyboardpre + "esc";
        }

        public static class media
        {
            private const string mediapre = mediapackage + ".";

            /// <summary>
            ///  切换播放暂停
            /// </summary>
            public const string toggleplaypause = mediapre + "toggleplaypause";

            /// <summary>
            /// 快进
            /// </summary>
            public const string fastforward = mediapre + "fastforward";

            /// <summary>
            /// 快退
            /// </summary>
            public const string fastbackward = mediapre + "fastbackward";

            /// <summary>
            /// 大步快进
            /// </summary>
            public const string veryfastforward = mediapre + "veryfastforward";

            /// <summary>
            /// 大步快退
            /// </summary>
            public const string veryfastbackward = mediapre + "veryfastbackward";

            /// <summary>
            /// 前进
            /// </summary>
            public const string forward = mediapre + "forward";

            /// <summary>
            /// 前退
            /// </summary>
            public const string backward = mediapre + "backward";

            /// <summary>
            /// 提高音量
            /// </summary>
            public const string increasevolume = mediapre + "increasevolume";

            /// <summary>
            /// 降低音量
            /// </summary>
            public const string decreasevolume = mediapre + "decreasevolume";

            /// <summary>
            /// 静音
            /// </summary>
            public const string mutevolume = mediapre + "mutevolume";

            /// <summary>
            /// 上一集
            /// </summary>
            public const string previoustrack = mediapre + "previoustrack";

            /// <summary>
            /// 下一集
            /// </summary>
            public const string nexttrack = mediapre + "nexttrack ";

            /// <summary>
            /// 停止
            /// </summary>
            public const string stop = mediapre + "stop";

            /// <summary>
            /// 全屏
            /// </summary>
            public const string fullscreen = mediapre + "fullscreen";
        }
    }
}
复制代码
 
客户端通信代码实现
view code
 public class sendcommandcompletedeventargs : eventargs
    {
        public bool success { get; internal set; }
        public string errmessage { get; internal set; }
    }

    public class client
    {
        const int actionsize = 32;
        const int buffersize = 1024;

        public event eventhandler<sendcommandcompletedeventargs> sendcommandcompleted;

        private void onsendcommandcompleted(sendcommandcompletedeventargs e)
        {
            eventhandler<sendcommandcompletedeventargs> handler = sendcommandcompleted;
            if (handler != null) handler(this, e);
        }

        public client()
        {

        }

        public void sendcommandasync(endpoint endpoint, string action, string command)
        {
            var actionbuffer = encoding.utf8.getbytes(action);
            var contextbuffer = encoding.utf8.getbytes(command);

            var buffersize = contextbuffer.length + actionsize + 4;
            var lengthbuffer = bitconverter.getbytes(contextbuffer.length);

            var buffer = new byte[buffersize];
            int offset = 0;
            array.copy(lengthbuffer, 0, buffer, offset, lengthbuffer.length);
            offset += 4;
            array.clear(buffer, offset, actionsize);
            array.copy(actionbuffer, 0, buffer, offset, actionbuffer.length);
            offset += actionsize;
            array.copy(contextbuffer, 0, buffer, offset, contextbuffer.length);

            var socketasynceventargs = new socketasynceventargs
                                           {
                                               usertoken =
                                                   new socket(addressfamily.internetwork, sockettype.stream,
                                                              protocoltype.tcp)
                                           };
            socketasynceventargs.completed += asynccompleted;
            socketasynceventargs.setbuffer(buffer, 0, buffersize);
            socketasynceventargs.remoteendpoint = endpoint;
            processconnect(socketasynceventargs);
        }

        #region private
        private void processconnect(socketasynceventargs e)
        {
            var socket = (socket)e.usertoken;
            bool willraiseevent = socket.connectasync(e);
            if (!willraiseevent)
            {
                connectcompleted(e);
            }
        }

        private void processsend(socketasynceventargs e)
        {
            var socket = (socket)e.usertoken;
            bool willraiseevent = socket.sendasync(e);
            if (!willraiseevent)
            {
                sendcompleted(e);
            }
        }

        private void asynccompleted(object sender, socketasynceventargs e)
        {
            switch (e.lastoperation)
            {
                case socketasyncoperation.connect:
                    connectcompleted(e);
                    break;
                case socketasyncoperation.send:
                    sendcompleted(e);
                    break;
                case socketasyncoperation.receive:
                    receivecompleted(e);
                    break;
                default:
                    return;
            }

        }

        private void receivecompleted(socketasynceventargs e)
        {
        }
        private void connectcompleted(socketasynceventargs e)
        {
            if (e.socketerror == socketerror.success)
            {
                processsend(e);
            }
            else
            {
                onsendcommandcompleted(new sendcommandcompletedeventargs { success = false, errmessage = "接收器无法连接" });
            }
        }

        private void sendcompleted(socketasynceventargs e)
        {
            var socket = (socket)e.usertoken;
            socket.close();
            if (e.socketerror == socketerror.success)
            {
                onsendcommandcompleted(new sendcommandcompletedeventargs { success = true });
            }
            else
            {
                onsendcommandcompleted(new sendcommandcompletedeventargs { success = false, errmessage = "发送命令失败" });
            }

        }
        #endregion

    }
复制代码


作者 fengyarongaa