zoukankan      html  css  js  c++  java
  • Windows Phone 7 网络编程之使用Socket(芒果更新)

           芒果更新的Windows Phone 7.1版本的API提供了Socket编程的接口,这给Windows Phone 7的网络开发又添加了一把利器,对于Windows Phone 7上的聊天软件开发是一件非常happy的事情。下面用一个小例子来演示一下Windows Phone 7上的Socket编程。用Windows Phone 7上的客户端程序作为Socket客户端,Windows控制台程序作为服务器端,ip取你电脑本机的ip,端口号用8888,实现了Windows Phone 7客户端向服务器端发送消息和接收消息的功能。
    先来看看演示的效果
    (1)       Windows Phone 7客户端客户端的实现。
    MainPage.xaml
    <phone:PhoneApplicationPage
    x:Class="SocketTest.MainPage"
    xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone
    ="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell
    ="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d
    ="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc
    ="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable
    ="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily
    ="{StaticResource PhoneFontFamilyNormal}"
    FontSize
    ="{StaticResource PhoneFontSizeNormal}"
    Foreground
    ="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations
    ="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible
    ="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
    <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
    <TextBlock x:Name="PageTitle" Text="Socket测试" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

    <TextBlock FontSize="30" Text="主机IP:" Margin="12,23,0,540" HorizontalAlignment="Left" Width="99" />
    <TextBox x:Name="Host" InputScope="Digits" HorizontalAlignment="Stretch" Text="192.168.1.102" Margin="110,6,0,523" />
    <TextBlock FontSize="30" Text="端口号:" Margin="9,102,345,451" />
    <TextBox x:Name="Port" InputScope="Digits"
    HorizontalAlignment
    ="Stretch"
    Text
    ="8888" Margin="110,90,0,433" />
    <TextBlock FontSize="30" Text="发送的消息内容:" Margin="6,180,157,374" />
    <TextBox x:Name="Message"
    HorizontalAlignment
    ="Stretch" Margin="-6,226,6,300" />
    <Button x:Name="SendButton"
    Content
    ="发送"
    Click
    ="SendButton_Click" Margin="0,509,12,6" />
    <ListBox Height="190" HorizontalAlignment="Left" Margin="-4,313,0,0" Name="listBox1" VerticalAlignment="Top" Width="460" />
    </Grid>
    </Grid>

    </phone:PhoneApplicationPage>
     
    cs页面
    using System;
    using System.Net;
    using System.Windows;
    using Microsoft.Phone.Controls;
    using System.Text;
    using System.Net.Sockets;

    namespace SocketTest
    {
    public partial class MainPage : PhoneApplicationPage
    {
    public MainPage()
    {
    InitializeComponent();
    }

    private void SendButton_Click(object sender, RoutedEventArgs e)
    {
    // 判断是否已经输入了IP地址和端口
    if (string.IsNullOrEmpty(Host.Text) || string.IsNullOrEmpty(Port.Text))
    {
    MessageBox.Show(
    "麻烦输入以下主机IP和端口号,谢谢!");
    return;
    }
    //主机IP地址
    string host = Host.Text.Trim();
    //端口号
    int port = Convert.ToInt32(Port.Text.Trim());
    //建立一个终结点对像
    DnsEndPoint hostEntry = new DnsEndPoint(host, port);
    //创建一个Socket对象
    Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    //创建一个Socket异步事件参数
    SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
    //将消息内容转化为发送的byte[]格式
    byte[] buffer = Encoding.UTF8.GetBytes(Message.Text);
    //将发送内容的信息存放进Socket异步事件参数中
    socketEventArg.SetBuffer(buffer, 0, buffer.Length);
    //注册Socket完成事件
    socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(SocketAsyncEventArgs_Completed);
    //设置Socket异步事件参数的Socket远程终结点
    socketEventArg.RemoteEndPoint = hostEntry;
    //将定义好的Socket对象赋值给Socket异步事件参数的运行实例属性
    socketEventArg.UserToken = sock;

    try
    {
    //运行Socket
    sock.ConnectAsync(socketEventArg);
    }
    catch (SocketException ex)
    {
    throw new SocketException((int)ex.ErrorCode);
    }

    }

    private void SocketAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e)
    {
    // 检查是否发送出错
    if (e.SocketError != SocketError.Success)
    {
    if (e.SocketError == SocketError.ConnectionAborted)
    {
    Dispatcher.BeginInvoke(()
    => MessageBox.Show("连接超时请重试! "
    + e.SocketError));
    }
    else if (e.SocketError == SocketError.ConnectionRefused)
    {
    Dispatcher.BeginInvoke(()
    => MessageBox.Show("服务器端问启动"
    + e.SocketError));
    }
    else
    {
    Dispatcher.BeginInvoke(()
    => MessageBox.Show("出错了"
    + e.SocketError));
    }

    //关闭连接清理资源
    if (e.UserToken != null)
    {
    Socket sock
    = e.UserToken as Socket;
    sock.Shutdown(SocketShutdown.Both);
    sock.Close();
    }
    return;

    }

    //检查Socket的当前最后的一个操作
    switch (e.LastOperation)
    {
    //如果最后的一个操作是连接,那么下一步处理就是发送消息。
    case SocketAsyncOperation.Connect:
    if (e.UserToken != null)
    {
    //获取运行中的Socket对象
    Socket sock = e.UserToken as Socket;
    //开始发送
    bool completesAsynchronously = sock.SendAsync(e);
    //检查socket发送是否被挂起,如果被挂起将继续进行处理
    if (!completesAsynchronously)
    {
    SocketAsyncEventArgs_Completed(e.UserToken, e);
    }
    };
    break;
    //如果最后的一个操作是发送,那么显示刚才发送成功的消息,然后开始下一步处理就是接收消息。
    case SocketAsyncOperation.Send:
    //将已成功发送的消息内容绑定到listBox1控件中
    Dispatcher.BeginInvoke(() =>
    {
    listBox1.Items.Add(
    "客户端" + DateTime.Now.ToShortTimeString() + "发送的消息 :" + Message.Text);
    }
    );
    if (e.UserToken != null)
    {
    //获取运行中的Socket对象
    Socket sock = e.UserToken as Socket;
    //开始接收服务器端的消息
    bool completesAsynchronously = sock.ReceiveAsync(e);
    //检查socket发送是否被挂起,如果被挂起将继续进行处理
    if (!completesAsynchronously)
    {
    SocketAsyncEventArgs_Completed(e.UserToken, e);
    }
    }
    break;
    //如果是最后的一个操作时接收,那么显示接收到的消息内容,并清理资源。
    case SocketAsyncOperation.Receive:
    if (e.UserToken != null)
    {
    //获取接收到的消息,并转化为字符串
    string dataFromServer = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
    //获取运行中的Socket对象
    Socket sock = e.UserToken as Socket;
    //将接收到的消息内容绑定到listBox1控件中
    Dispatcher.BeginInvoke(() =>
    {
    listBox1.Items.Add(
    "服务器端" + DateTime.Now.ToShortTimeString() + "传过来的消息:" + dataFromServer);
    });
    }
    break;
    }
    }
    }
    }
    (2)       Socket服务器端的实现,使用Windows的控制台程序。
    using System;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;

    namespace SocketServer
    {
    static class Program
    {

    private static AutoResetEvent _flipFlop = new AutoResetEvent(false);

    static void Main(string[] args)
    {
    //创建socket,使用的是TCP协议,如果用UDP协议,则要用SocketType.Dgram类型的Socket
    Socket listener = new Socket(AddressFamily.InterNetwork,
    SocketType.Stream,
    ProtocolType.Tcp);

    //创建终结点EndPoint 取当前主机的ip
    IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
    //把ip和端口转化为IPEndpoint实例,端口号取8888
    IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList.First(), 8888);

    Console.WriteLine(
    "本地的IP地址和端口是 : {0}", localEP);

    try
    {
    //绑定EndPoint对像(8888端口和ip地址)
    listener.Bind(localEP);
    //开始监听
    listener.Listen(10);
    //一直循环接收客户端的消息
    while (true)
    {
    Console.WriteLine(
    "等待Windows Phone客户端的连接...");
    //开始接收下一个连接
    listener.BeginAccept(AcceptCallback, listener);
    //开始线程等待
    _flipFlop.WaitOne();
    }
    }
    catch (Exception e)
    {
    Console.WriteLine(e.ToString());
    }

    }

    /// <summary>
    /// 接收返回事件处理
    /// </summary>
    /// <param name="ar"></param>
    private static void AcceptCallback(IAsyncResult ar)
    {
    Socket listener
    = (Socket)ar.AsyncState;
    Socket socket
    = listener.EndAccept(ar);

    Console.WriteLine(
    "连接到Windows Phone客户端。");

    _flipFlop.Set();

    //开始接收,传递StateObject对象过去
    var state = new StateObject();
    state.Socket
    = socket;
    socket.BeginReceive(state.Buffer,
    0,
    StateObject.BufferSize,
    0,
    ReceiveCallback,
    state);
    }

    private static void ReceiveCallback(IAsyncResult ar)
    {
    StateObject state
    = (StateObject)ar.AsyncState;
    Socket socket
    = state.Socket;


    // 读取客户端socket发送过来的数据
    int read = socket.EndReceive(ar);

    // 如果成功读取了客户端socket发送过来的数据
    if (read > 0)
    {
    //获取客户端的消息,转化为字符串格式
    string chunk = Encoding.UTF8.GetString(state.Buffer, 0, read);
    state.StringBuilder.Append(chunk);

    if (state.StringBuilder.Length > 0)
    {
    string result = state.StringBuilder.ToString();
    Console.WriteLine(
    "收到客户端传过来的消息: {0}", result);
    //发送数据信息给客户端
    Send(socket, result);
    }
    }
    }


    /// <summary>
    /// 返回客户端数据
    /// </summary>
    /// <param name="handler"></param>
    /// <param name="data"></param>
    private static void Send(Socket handler, String data)
    {

    //将消息内容转化为发送的byte[]格式
    byte[] byteData = Encoding.UTF8.GetBytes(data);

    //发送消息到Windows Phone客户端
    handler.BeginSend(byteData, 0, byteData.Length, 0,
    new AsyncCallback(SendCallback), handler);
    }

    private static void SendCallback(IAsyncResult ar)
    {
    try
    {
    Socket handler
    = (Socket)ar.AsyncState;
    // 完成发送消息到Windows Phone客户端
    int bytesSent = handler.EndSend(ar);
    if (bytesSent > 0)
    {
    Console.WriteLine(
    "发送成功!");
    }
    }
    catch (Exception e)
    {
    Console.WriteLine(e.ToString());
    }
    }
    }

    public class StateObject
    {
    public Socket Socket;
    public StringBuilder StringBuilder = new StringBuilder();
    public const int BufferSize = 10;
    public byte[] Buffer = new byte[BufferSize];
    public int TotalSize;
    }
    }
     
    ok了。。。晚安!
  • 相关阅读:
    微信小程序入门注意
    回调函数理解实例
    2017最新教程--如何下载美拍视频
    tomcat如何利用waf进行防护
    深入理解正则表达式-----应用于检测csrf的正则表达式
    snort安装--daq,dnet---ERROR! dnet header not found, go get it from...等错误解决方案
    先知安全技术社区原创文章奖励计划
    谈一谈情报威胁与态势感知
    pfring破解DNA限制
    八皇后--python代码
  • 原文地址:https://www.cnblogs.com/linzheng/p/2086456.html
Copyright © 2011-2022 走看看