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。