[C#][Silverlight] Silverlight與視窗應用程式溝通
最近我想試試看實作HTTP伺服器在使用者電腦,讓使用者以網頁方式跟自己電腦上的HTTP伺服器作互動,藉此來操控應用程式等等的東西。因為是自行實作HTTP伺服器,也就是說只有簡單的HTTP標準能力,在互動上就稍嫌麻煩,因此我就想試試看Microsoft近年一直在推的Silverlight,Silverlight是網頁透過網頁外掛的方式呈現,可以取得Browser的資訊並且可以當作在客端電腦上互動的媒介,不然一般必須靠Java或Flash來達成。但是Silverlight的類別庫跟.Net Framework的一般類別庫是分開的,僅有簡單的Socket進行TCP通訊協定可以使用,以下是Socket在TCP模式下與本機的另外一隻Windows Form應用程式進行溝通的範例。
PS:由於Silverlight有安全考量的問題,如果直接使用下方範例一定會造成例外狀況,請參考[Socket 連線–Error Code 10013 嘗試存取通訊端被拒絕,因為存取權限不足。 解決方案]。
[完整範例程式碼下載:SilverlightSocketDemo.zip]
※全文歡迎轉載但請註明出處,謝謝。※
因為Server端的寫法跟原本TcpListener的用法一樣,因此僅貼出Silverlight的程式碼,若要方便進行測試可以點擊上方連結下載完整程式碼。
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
//非同步作業所要使用的資料。
SocketAsyncEventArgs _AsyncEventArgs = new SocketAsyncEventArgs();
Socket _Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
//由於部落格另外一篇文章是使用TCP來作範例,這邊也使用TCP來作示範。
_AsyncEventArgs.SocketClientAccessPolicyProtocol = SocketClientAccessPolicyProtocol.Tcp;
_AsyncEventArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4525);
_AsyncEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(AsyncEventArgs_Completed);
_AsyncEventArgs.UserToken = _Socket;
//開始Socket的非同步連線作業。
_Socket.ConnectAsync(_AsyncEventArgs);
}
ManualResetEvent _Done = new ManualResetEvent(false);
//非同步作業完畢之後引發此方法
private void AsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e)
{
//若事件資料顯示成功則執行
if (e.SocketError == SocketError.Success)
{
//因為Connect、Receive、Send可以使用同一份非同步事件資料進行,所以也提供了方式查詢這次的擲回是做完哪件事情。
switch (e.LastOperation)
{
case SocketAsyncOperation.Connect:
{
//連線完成之後開始進行接收,這邊要特別注意非同步事件資料的緩衝區原本是null,
//若是不透過SetBuffer方法進行宣告就直接呼叫ReceiveAsync方法,會造成Socket直接關閉。
_AsyncEventArgs.SetBuffer(new Byte[1024], 0, 1024);
_Socket.ReceiveAsync(_AsyncEventArgs);
break;
}
case SocketAsyncOperation.Receive:
{
_Done.Reset();
this.Dispatcher.BeginInvoke(new Action(() =>
{
textBox1.Text += (Encoding.Unicode.GetString(e.Buffer, 0, e.BytesTransferred)) + "\r\n";
textBox1.Select(textBox1.Text.Length, 0);
_Done.Set();
}));
_Done.WaitOne();
//接收到伺服器端的資料之後我們在客端也回傳一份回應回去
String m_Message = String.Format("I got {0} byte(s).", e.BytesTransferred);
Byte[] m_MessageData = Encoding.Unicode.GetBytes(m_Message);
//這邊利用SetBuffer將要傳送的資料陣列丟進非同步作業資料裡面。
_AsyncEventArgs.SetBuffer(m_MessageData, 0, m_MessageData.Length);
//並且呼叫SendAsync方法進行非同步傳送。
_Socket.SendAsync(_AsyncEventArgs);
break;
}
case SocketAsyncOperation.Send:
{
_AsyncEventArgs.SetBuffer(new Byte[1024], 0, 1024);
_Socket.ReceiveAsync(_AsyncEventArgs);
break;
}
}
}
//失敗則顯示例外狀況。
else
this.Dispatcher.BeginInvoke(new Action(() =>
{ MessageBox.Show(new SocketException((int)e.SocketError).Message); }));
}
}