芒果更新的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异步事件参数的运行实例属性
-
socksocketEventArg.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,
- ,
- StateObject.BufferSize,
- ,
- 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;
- }
- }
本文转自linzheng 51CTO博客,原文链接:http://blog.51cto.com/linzheng/1078573