Windows Phone 7的Socket类型修改自Silverlight中的Socket类型。总体来说,相比桌面完整.NET中的Socket类型,它的阉割程度相当大。
首先所有操作只能是异步的,而且不同于传统Socket类型的APM异步方法(比如BeginConnect,BeginSend等),他使用了一种类似EAP的模式,典型的EAP模式异步调用比如是WebClient的DownloadStringAsync方法和它的DownloadStringCompleted事件。不过Windows Phone 7中的Socket类型本身没有定义任何事件,而是把事件定义在一个叫SocketAsyncEventArgs类型中。
那么这种Socket类型的工作流程是这样的。首先初始化一个SocketAsyncEventArgs类型,设置相应的属性,比如如果进行连接操作,那么设置SocketAsyncEventArgs.RemoteEndPoint属性,如果想发送数据,需调用SocketAsyncEventArgs类型的SetBuffer方法设置内部Buffer。
接下来,注册SocketAsyncEventArgs类型的Completed事件,因为Socket类型的所有操作都是异步的,因此必须注册这个事件从而获取异步操作的结果。Completed事件的委托类型是EventHandler<SocketAsyncEventArgs>,也就是说它会把自己作为EventArgs。
最后,在Completed事件中,通过SocketAsyncEventArgs对象的一些属性来获取你需要的数据(感觉这样过分得使用一个EventArgs类型有些别扭)。比如SocketAsyncEventArgs.SocketError属性返回操作结果。如果你调用的是Socket.ReceiveAsync方法,你需要SocketAsyncEventArgs.Buffer属性。另外注意,如果SocketError等于Success的话,那么代表着操作成功。(什么?SocketError.Success?那还是Error吗?哈哈,我也不知道谁定义的它,也算另一个吐槽点吧)
来段演示代码吧,比如我们需要异步连接到远程,需要调用Socket.ConnectAsync方法,如下:
//创建SocketAsyncEventArgs
var socketArgs = new SocketAsyncEventArgs();
//设置连接的IP地址和端口号
socketArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Parse("123.123.123.123"), 1033);
//注册Completed事件
socketArgs.Completed += socketArgs_Completed;
//开始操作
//socket变量是Socket对象
socket.ConnectAsync(socketArgs);
然后是Completed事件方法:
void socketArgs_Completed(object sender, SocketAsyncEventArgs e)
{
//判断是否成功
if (e.SocketError == SocketError.Success)
{
//获取远程连接IP和端口号(IPEndPoint对象)
var endPoint = e.RemoteEndPoint;
}
else
{
//抛出SocketException
throw new SocketException((int)e.SocketError);
}
}
可以看到,在Completed事件中,上面代码会先判断SocketAsyncEventArgs.SocketError属性,如果不成功的话,抛出SocketException异常。
还有一些非常致命的问题,Windows Phone 7中的Socket没有任何TCP监听的方法。没有Listen没有Accept方法。同时SocketAsyncEventArgs类型中只有RemoteEndPoint属性而没有LocalEndPoint属性。太无奈了。不过好消息是Windows Phone 8和Windows 8中可以进行更完善的Socket操作了。
更新:
又写了一篇关于Windows Phone 7 Socket的文章:
在Windows Phone 7环境下执行NetworkStream类型
又发现一点,Socket.ConnectAsync貌似总会成功,即便是对应的RemoteEndPoint根本没有TCP监听,而且此时Socket的RemoteEndPoint和Connected都会是连接成功的结果,但实际上根本没有连接成功。等真正调用SendAsync后,才会返回SocketError.NotConnected。