运维开发网

Socket Server in Windows Phone 8

运维开发网 https://www.qedev.com 2020-07-21 09:20 出处:网络 作者:运维开发网整理
从Windows Phone 8 开始,Socket 的支持扩大到允许开发者撰写Socket Server,也就是说,在不透过中介服务的情况下,开发者可以撰写一个Windows Phone Server Application来允许其它设备连入, 这在开发对战连线游戏时是个非常有用的机制。 文/黄忠成 Socket Support in Windows Phone 8 ? 从Windows Pho

从Windows Phone 8 开始,Socket 的支持扩大到允许开发者撰写Socket Server,也就是说,在不透过中介服务的情况下,开发者可以撰写一个Windows Phone Server Application来允许其它设备连入,

这在开发对战连线游戏时是个非常有用的机制。

文/黄忠成

Socket Support in Windows Phone 8

? 从Windows Phone 7.1开始便支持了Socket Programming,开发者可以直接使用Socket来开发需要快速通讯的网络应用程序,不过那时Socket仅支持到Client-Side,简单的说就是你无法在Windows Phone上建立一个Socket Server

来接入其它的Windows Phone App连线,必须透过一个由其它平台所提供的中介服务(像是Windows Client、网站等等),这大大的限制了Windows Phone Apps Socket的应用范围。

? 从Windows Phone 8 开始,Socket 的支持扩大到允许开发者撰写Socket Server,也就是说,在不透过中介服务的情况下,开发者可以撰写一个Windows Phone Server Application来允许其它设备连入,

这在开发对战连线游戏时是个非常有用的机制。

A Simple Socket Listener

? 用法很简单,你只需要利用StreamSocketListener来建立一个Server Socket,就可以接入来自其它设备的连线,如以下程序。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Navigation;

using Microsoft.Phone.Controls;

using Microsoft.Phone.Shell;

using SocketServer.Resources;

using Windows.Networking.Sockets;

using Windows.Storage.Streams;

using Windows.Networking;

using Windows.Networking.Connectivity;

using System.Text;


namespace SocketServer

{

    public class ListenInformation

    {

        public HostName Host { get; set; }

        public string DisplayName { get; set; }

    }


    public partial class MainPage : PhoneApplicationPage

    {

        private StreamSocketListener _listener = new StreamSocketListener();

        private List _ips = new List();

        // Constructor

        public MainPage()

        {

            InitializeComponent();

            var hostNames = NetworkInformation.GetHostNames();

            foreach (HostName hn in hostNames)

            {

                ListenInformation info = new ListenInformation() { Host = hn };

                if (hn.IPInformation.NetworkAdapter.IanaInterfaceType == 71) //Wi-Fi

                    info.DisplayName = hn.CanonicalName + "(Wi-Fi)";

                else if (hn.IPInformation.NetworkAdapter.IanaInterfaceType == 244) //cellular

                    info.DisplayName = hn.CanonicalName + "(cellular)";

                else

                    info.DisplayName = hn.CanonicalName;

                _ips.Add(info);

            }

            lstIPs.DisplayMemberPath = "DisplayName";

            lstIPs.ItemsSource = _ips;

        }


        async private void WaitForData(StreamSocket socket)

        {

            var dr = new DataReader(socket.InputStream);

            var dataReaded = await dr.LoadAsync(sizeof(uint));


            if (dataReaded == 0)

                return;


            uint strLen = dr.ReadUInt32();

            await dr.LoadAsync(strLen);

            string msg = dr.ReadString(strLen);

            if (msg.ToLower().Equals("bye"))

            {

                socket.Dispose();

                return;

            }

            Dispatcher.BeginInvoke(() =>

                {

                    lstOutput.Items.Add("recv:" + msg);

                });

            WaitForData(socket);

        }




        void listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)

        {           

           WaitForData(args.Socket);

        }


        private async void Button_Click(object sender, RoutedEventArgs e)

        {

            if (lstIPs.SelectedItem != null)

            {

                ((Button)sender).IsEnabled = false;

                _listener.ConnectionReceived += listener_ConnectionReceived;

                await _listener.BindEndpointAsync(((ListenInformation)lstIPs.SelectedItem).Host, "1067");


                appTitle.Text = "listen on " + _listener.Information.LocalPort;

            }

            else

                MessageBox.Show("please select a ip to listen.");

        }

    }

}

让我稍微解释一下这个程序几个关键片段。

public MainPage()

        {

            InitializeComponent();

            var hostNames = NetworkInformation.GetHostNames();

            foreach (HostName hn in hostNames)

            {

                ListenInformation info = new ListenInformation() { Host = hn };

                if (hn.IPInformation.NetworkAdapter.IanaInterfaceType == 71) //Wi-Fi

                    info.DisplayName = hn.CanonicalName + "(Wi-Fi)";

                else if (hn.IPInformation.NetworkAdapter.IanaInterfaceType == 244) //cellular

                    info.DisplayName = hn.CanonicalName + "(cellular)";

                else

                    info.DisplayName = hn.CanonicalName;

                _ips.Add(info);

            }

            lstIPs.DisplayMemberPath = "DisplayName";

            lstIPs.ItemsSource = _ips;

        }

理论上,每个Windows Phone 8设备应该都会有一个以上的网络位址,除非该设备没有数据连线及Wi-Fi,因此要起始一个Socket Server,得先决定要系结至哪个网络位址,这里透过GetHostNames()来取得所有可用的网络位址,

然后透过IanaInterfaceType来标示该网络位址的型态,一般来说, 71是Wi-Fi、244是数据连线。

private async void Button_Click(object sender, RoutedEventArgs e)

        {

            if (lstIPs.SelectedItem != null)

            {

                ((Button)sender).IsEnabled = false;

                _listener.ConnectionReceived += listener_ConnectionReceived;

                await _listener.BindEndpointAsync(((ListenInformation)lstIPs.SelectedItem).Host, "1067");


                appTitle.Text = "listen on " + _listener.Information.LocalPort;

            }

            else

                MessageBox.Show("please select a ip to listen.");

        }

当使用者选择了要系结的网络位址后,这里透过BindEndpointAsync来启用Socket Server,第一个参数是HostName,第二个则是要聆听的Port资讯。

当连线接入时,ConnectionReceived事件会触发,在此处透过DataReader来读入由Client端传入的数据。

async private void WaitForData(StreamSocket socket)

        {

            var dr = new DataReader(socket.InputStream);

            var dataReaded = await dr.LoadAsync(sizeof(uint));


            if (dataReaded == 0)

                return;


            uint strLen = dr.ReadUInt32();

            await dr.LoadAsync(strLen);

            string msg = dr.ReadString(strLen);

            if (msg.ToLower().Equals("bye"))

            {

                socket.Dispose();

                return;

            }

            Dispatcher.BeginInvoke(() =>

                {

                    lstOutput.Items.Add("recv:" + msg);

                });

            WaitForData(socket);

        }




        void listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)

        {           

           WaitForData(args.Socket);

        }

Client: Windows Phone 8

? 完成Server端后,Client端相对简单多了。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Navigation;

using Microsoft.Phone.Controls;

using Microsoft.Phone.Shell;

using ClientSocketDemo.Resources;

using Windows.Networking.Sockets;

using Windows.Networking;

using Windows.Storage.Streams;


namespace ClientSocketDemo

{

    public partial class MainPage : PhoneApplicationPage

    {

        private StreamSocket _socket = null;


        // Constructor

        public MainPage()

        {

            InitializeComponent();


            // Sample code to localize the ApplicationBar

            //BuildLocalizedApplicationBar();

        }


        private async void Button_Click(object sender, RoutedEventArgs e)

        {

            _socket = new StreamSocket();

            await _socket.ConnectAsync(new HostName(txtIP.Text), "1067");

            ((Button)sender).IsEnabled = false;

            txtIP.IsEnabled = false;

            btnSend.IsEnabled = true;

            txtSendData.IsEnabled = true;           

        }


        private async void btnSend_Click(object sender, RoutedEventArgs e)

        {

            DataWriter dr = new DataWriter(_socket.OutputStream);

            string data = txtSendData.Text;

            dr.WriteUInt32((uint)data.Length);

            await dr.StoreAsync();

            dr.WriteString(data);

            await dr.StoreAsync();

            dr.DetachStream();

        }

    }

}

透过ConnectAsync可以连接至Socket Server,第一个参数是HostName(IP),第二个是Port。

图1

Socket Server in Windows Phone 8

Client: Windows 8 App

? 同理,你也可以撰写Windows Store App的客户端来连入Windows Phone。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;


namespace WinSocketClient
{
  
    public sealed partial class MainPage : Page
    {
        private StreamSocket _socket = null;

        public MainPage()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            _socket = new StreamSocket();
            await _socket.ConnectAsync(new HostName(txtIP.Text), "1067");
            ((Button)sender).IsEnabled = false;
            txtIP.IsEnabled = false;
            btnSend.IsEnabled = true;
            txtSendData.IsEnabled = true;
        }

        private async void btnSend_Click(object sender, RoutedEventArgs e)
        {
            DataWriter dr = new DataWriter(_socket.OutputStream);
            string data = txtSendData.Text;
            dr.WriteUInt32((uint)data.Length);
            await dr.StoreAsync();
            dr.WriteString(data);
            await dr.StoreAsync();
            dr.DetachStream();
        }

    }
}

图2

Socket Server in Windows Phone 8

原文:大专栏  Socket Server in Windows Phone 8

0

精彩评论

暂无评论...
验证码 换一张
取 消