新时尚Windows8开发(40):StreamSocket的使用

来源:互联网 发布:mac eclipse自动补全 编辑:程序博客网 时间:2024/06/01 15:31
在Windows Store应用程序中使用Stram Socket与桌面客户端进行通信,一直没弄成功,总让俺觉得很震精,怎么会不成功呢。后来经过几回测试发现,原来是在DataReader那里出了问题,总算弄成了。

Stream Socket通常用于传输一些比较长的数据,如文件。但这里为了使演示变得更容易理解,我传输了一段字符。

首先,我们用WinForm做一个服务器端。界面不复杂,目的是侦听连接,收到传入的客户端连接后,向客户端发送一条字符串消息。

处理的逻辑代码如下:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using System.IO;using System.Net;using System.Net.Sockets;namespace TestServerApp{    public partial class Form1 : Form    {        TcpListener m_Listener = null;//用于监听链接        TcpClient m_Client = null;//传入的客户端        public Form1()        {            InitializeComponent();            this.btnStart.Enabled = true;            this.btnStop.Enabled = false;        }        /// <summary>        /// 向客户端发送字符串        /// </summary>        private void SendMessage(TcpClient client)        {            using (var stream = client.GetStream())            {                byte[] buffer = Encoding.UTF8.GetBytes("奔,不停地奔,奔向传说中的荒原;飞,不停地飞,飞向天空的那一端。");                uint len = (uint)buffer.Length;                // 先发送长度                stream.Write(BitConverter.GetBytes(len), 0, sizeof(uint));                // 再发送数据                stream.Write(buffer, 0, buffer.Length);                            }        }        private async void btnStart_Click(object sender, EventArgs e)        {            if (this.m_Listener == null)            {                this.m_Listener = new TcpListener(IPAddress.Parse(this.txtAddr.Text), Convert.ToInt32(this.udPort.Value));            }            this.m_Listener.Start();            this.lblMsg.Text = "监听已开始。";            this.btnStart.Enabled = false;            this.btnStop.Enabled = true;            try            {                m_Client = await m_Listener.AcceptTcpClientAsync();                SendMessage(m_Client);            }            catch (SocketException se)            {                this.lblMsg.Text = se.Message;            }            catch (Exception ex)            {                this.lblMsg.Text = ex.Message;            }        }        private void btnStop_Click(object sender, EventArgs e)        {            if (m_Listener != null)            {                m_Listener.Stop();                this.lblMsg.Text = "监听已停止。";            }            this.btnStart.Enabled = true;            this.btnStop.Enabled = false;        }    }}

 

接着是Win8 App客户端。

因为我们要使用网络连接,在创建项目后,把开清单文件,切换到【功能】选项卡,把和网络连接有关的选项勾上。

 

打开主页MainPage的XAML代码编辑器(设计视图),简单布局一下界面。

<Page    x:Class="WCleintApp.MainPage"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:local="using:WCleintApp"    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    mc:Ignorable="d">    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">        <Grid.RowDefinitions>            <RowDefinition Height="Auto"/>            <RowDefinition Height="*"/>        </Grid.RowDefinitions>        <Grid Grid.Row="0" Margin="3">            <Grid.RowDefinitions>                <RowDefinition Height="auto"/>                <RowDefinition Height="auto"/>            </Grid.RowDefinitions>            <Grid.ColumnDefinitions>                <ColumnDefinition Width="auto"/>                <ColumnDefinition Width="*"/>            </Grid.ColumnDefinitions>            <TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Text="服务器:"/>            <TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Text="端口:"/>            <TextBox x:Name="txtServer" Grid.Row="0" Grid.Column="1" Margin="2,3"/>            <TextBox x:Name="txtPort" Grid.Row="1" Grid.Column="1" Margin="2,3"/>        </Grid>        <StackPanel Grid.Row="1" Margin="5">            <Button Content="连接" Click="onConnClick" Margin="3,8,0,12" Padding="4,2.5"/>            <TextBox x:Name="txtRec" Margin="5,7,0,0" Height="200" IsReadOnly="True"/>        </StackPanel>    </Grid></Page>


切换到隐藏代码视图,完成功能代码。

using System;using System.Collections.Generic;using System.IO;
........
using Windows.UI.Xaml.Navigation;using Windows.Networking;using Windows.Networking.Sockets;using Windows.Storage.Streams;namespace WCleintApp{    /// <summary>    /// 可用于自身或导航至 Frame 内部的空白页。    /// </summary>    public sealed partial class MainPage : Page    {        StreamSocket mSocket = null;//局部变量        bool isConnected; //标识是否已经进行了连接        public MainPage()        {            this.InitializeComponent();            this.isConnected = false;        }        private async void onConnClick(object sender, RoutedEventArgs e)        {            if (mSocket ==null)            {                mSocket = new StreamSocket();            }            // 如果还没连接就进行连接            if (this.isConnected == false)            {                HostName hServer = new HostName(txtServer.Text);                try                {                    await mSocket.ConnectAsync(hServer, txtPort.Text);                    this.isConnected = true;                }                catch { this.isConnected = false; }            }            DataReader dr =  new DataReader(mSocket.InputStream);            // ByteOrder要设置为LittleEndian,不然会报错            dr.ByteOrder = ByteOrder.LittleEndian;            dr.UnicodeEncoding = UnicodeEncoding.Utf8;//编码            // 先读出一个uint的值,4个字节,这样就知道要接收数据的长度            var il = await dr.LoadAsync(sizeof(uint));            // 如果不相等,说明读到的不是uint值,因为必须4个字节            if (il != sizeof(uint))            {                txtRec.Text = "无法确定数据大小。";                return;            }            // 确定流中数据的长度            uint strlen = dr.ReadUInt32();            // 继续加载剩下的数据            await dr.LoadAsync(strlen);            txtRec.Text = dr.ReadString(strlen);            //必须与流分离,避免将整个流也释放            dr.DetachStream();            dr.Dispose();        }     }}


先运行服务器端,输入本机IP和监听端口,然后开始监听。

再运行客户端,输入服务器的IP和端口,进行连接,如果成功,就会收到服务器端发过来的字符串。

原创粉丝点击