Silverlight网络通信:从消息客户端到本地连接
在现代应用开发中,网络通信是实现应用功能的重要组成部分。Silverlight作为一种开发技术,提供了多种网络通信方式,本文将详细介绍Silverlight中的消息客户端和本地连接模型。
消息客户端
消息客户端在网络通信中承担着连接服务器、发送和接收消息的重要任务。在Silverlight中,由于没有
TcpClient
类,需要使用较低级别的
Socket
类来实现这些功能。
1. 连接服务器
当用户点击“连接”按钮时,客户端需要创建一个新的
Socket
对象和一个新的
SocketAsyncEventArgs
对象来建立与服务器的连接。具体步骤如下:
1.
关闭已打开的套接字
:如果套接字已经打开,则将其关闭。
2.
创建
DnsEndPoint
对象
:用于标识远程主机的位置。在本例中,远程主机是托管Silverlight页面的Web服务器,端口号为4530。
3.
创建
Socket
对象
:指定地址族、套接字类型和协议类型。
4.
创建并配置
SocketAsyncEventArgs
对象
:设置
UserToken
属性为对应的
Socket
对象,设置
RemoteEndPoint
属性为远程服务器的位置,并为
Completed
事件附加事件处理程序。
5.
启动异步连接过程
:调用
Socket
对象的
ConnectAsync
方法。
以下是实现连接服务器的代码:
' The socket for the underlying connection.
Private socket As Socket
Private Sub cmdConnect_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Try
If (socket IsNot Nothing) AndAlso (socket.Connected) Then
socket.Close()
End If
Catch err As Exception
AddMessage("ERROR: " & err.Message)
End Try
Dim endPoint As New DnsEndPoint( _
Application.Current.Host.Source.DnsSafeHost, 4530)
socket = New Socket(AddressFamily.InterNetwork, _
SocketType.Stream, ProtocolType.Tcp)
Dim args As New SocketAsyncEventArgs()
' To configure a SocketAsyncEventArgs object, you need to set
' the corresponding Socket object (in the UserToken property)
' and the location of the remote server (in the RemoteEndPoint property).
args.UserToken = socket
args.RemoteEndPoint = endPoint
' You must also attach an event handler for the Completed event.
AddHandler args.Completed, AddressOf OnSocketConnectCompleted
' Start the asynchronous connect process.
socket.ConnectAsync(args)
End Sub
如果要通过HTTP从IIS Web服务器下载策略文件,需要在调用
ConnectAsync
方法之前设置
SocketAsyncEventArgs
对象的
SocketClientAccessPolicyProtocol
属性:
args.SocketClientAccessPolicyProtocol = SocketClientAccessPolicyProtocol.Http
2. 发送消息
在聊天应用中,每条消息包含文本、发送者的姓名和发送时间。这些信息封装在一个自定义的
Message
类中。当用户输入文本并点击“发送”按钮时,需要创建一个新的
SocketAsyncEventArgs
对象,并将消息数据序列化后添加到该对象中。具体步骤如下:
1.
检查连接状态
:如果套接字未连接,则显示错误信息并返回。
2.
创建
MemoryStream
对象
:用于存储序列化后的数据。
3.
使用
XmlSerializer
序列化数据
:将
Message
对象序列化为流。
4.
将序列化后的数据转换为字节数组
:调用
MemoryStream
对象的
ToArray
方法。
5.
创建并配置
SocketAsyncEventArgs
对象
:将字节数组添加到
BufferList
属性中。
6.
发送消息
:调用
Socket
对象的
SendAsync
方法。
以下是实现发送消息的代码:
Private Sub cmdSend_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
If (socket Is Nothing) OrElse (socket.Connected = False) Then
AddMessage("ERROR: Not connected.")
Return
End If
' Create the MemoryStream where the serialized data will be placed.
Dim ms As New MemoryStream()
' Use the XmlSerializer to serialize the data.
Dim serializer As New XmlSerializer(GetType(Message))
serializer.Serialize(ms, New Message(txtMessage.Text, txtName.Text))
' Convert the serialized data in the MemoryStream to a byte array.
Dim messageData As Byte() = ms.ToArray()
' Place the byte array in the SocketAsyncEventArgs object,
' so it can be sent to the server.
Dim args As New SocketAsyncEventArgs()
Dim bufferList As New List(Of ArraySegment(Of Byte))()
bufferList.Add(New ArraySegment(Of Byte)(messageData))
args.BufferList = bufferList
' Send the message.
socket.SendAsync(args)
End Sub
3. 接收消息
当有消息发送到客户端时,
SocketAsyncEventArgs
对象的
Completed
事件会触发
OnSocketReceive
事件处理程序。在该处理程序中,需要反序列化消息、显示消息并继续监听更多消息。具体步骤如下:
1.
检查传输的字节数
:如果传输的字节数为0,则表示服务器已断开连接,关闭套接字并返回。
2.
反序列化消息
:使用
XmlSerializer
将接收到的数据反序列化为
Message
对象。
3.
显示消息
:将消息添加到消息列表中。
4.
继续监听更多消息
:调用
Socket
对象的
ReceiveAsync
方法。
以下是实现接收消息的代码:
Private Sub OnSocketReceive(ByVal sender As Object, ByVal e As SocketAsyncEventArgs)
If e.BytesTransferred = 0 Then
AddMessage("Server disconnected.")
Try
socket.Close()
Catch
End Try
Return
End If
Try
' Retrieve and display the message.
Dim serializer As New XmlSerializer(GetType(Message))
Dim ms As New MemoryStream()
ms.Write(e.Buffer, 0, e.BytesTransferred)
ms.Position = 0
Dim message As Message = CType(serializer.Deserialize(ms), Message)
AddMessage("[" & message.Sender & "] " & _
message.MessageText & _
" (at " & message.SendTime.ToLongTimeString() & ")")
Catch err As Exception
AddMessage("ERROR: " & err.Message)
End Try
' Listen for more messages.
socket.ReceiveAsync(e)
End Sub
本地连接
除了使用
Socket
类进行网络通信外,Silverlight还提供了一种更简单的通信机制:本地连接模型。该模型适用于在同一台计算机上运行的两个Silverlight应用程序之间的交互。
1. 发送消息
要发送消息,需要创建一个
LocalMessageSender
对象,并指定接收者的名称。发送消息的步骤如下:
1.
创建
LocalMessageSender
对象
:指定接收者的名称和可选的域名。
2.
发送消息
:调用
SendAsync
方法并传入消息字符串。
以下是实现发送消息的代码:
Private messageSender As New LocalMessageSender("EavesdropperReceiver")
Private Sub txt_KeyUp(ByVal sender As Object, ByVal e As KeyEventArgs)
messageSender.SendAsync(txt.Text)
End Sub
2. 接收消息
要接收消息,需要创建一个
LocalMessageReceiver
对象,并指定与发送者相同的接收者名称。接收消息的步骤如下:
1.
创建
LocalMessageReceiver
对象
:指定接收者的名称和可选的域名范围。
2.
附加事件处理程序
:为
MessageReceived
事件附加事件处理程序。
3.
开始监听
:调用
Listen
方法。
以下是实现接收消息的代码:
Private receiver As New LocalMessageReceiver("EavesdropperReceiver")
Private Sub Page_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
AddHandler receiver.MessageReceived, AddressOf receiver_MessageReceived
receiver.Listen()
End Sub
Private Sub receiver_MessageReceived(ByVal sender As Object, ByVal e As MessageReceivedEventArgs)
lblDisplay.Text = "The user of Main Application typed: """ & e.Message & """"
End Sub
总结
通过本文的介绍,我们了解了Silverlight中消息客户端和本地连接模型的实现方法。消息客户端使用
Socket
类实现了与服务器的连接、消息的发送和接收,而本地连接模型则提供了一种更简单的方式来实现同一台计算机上两个Silverlight应用程序之间的通信。这些技术为开发具有网络通信功能的Silverlight应用程序提供了有力的支持。
流程图
graph TD;
A[用户点击连接按钮] --> B[关闭已打开的套接字];
B --> C[创建DnsEndPoint对象];
C --> D[创建Socket对象];
D --> E[创建并配置SocketAsyncEventArgs对象];
E --> F[启动异步连接过程];
F --> G{连接成功?};
G -- 是 --> H[接收消息];
G -- 否 --> I[显示连接失败信息];
H --> J[用户输入消息并点击发送按钮];
J --> K[检查连接状态];
K -- 已连接 --> L[序列化消息数据];
L --> M[创建并配置SocketAsyncEventArgs对象];
M --> N[发送消息];
K -- 未连接 --> O[显示未连接错误信息];
N --> H;
表格
| 功能 | 实现方式 |
|---|---|
| 连接服务器 |
使用
Socket
类和
SocketAsyncEventArgs
对象进行异步连接
|
| 发送消息 |
创建
Message
类封装消息信息,使用
XmlSerializer
序列化数据,通过
Socket
类发送
|
| 接收消息 |
监听
SocketAsyncEventArgs
对象的
Completed
事件,反序列化消息并显示
|
| 本地连接发送消息 |
使用
LocalMessageSender
对象的
SendAsync
方法
|
| 本地连接接收消息 |
使用
LocalMessageReceiver
对象的
Listen
方法监听消息
|
进一步优化与拓展
消息客户端优化
虽然消息客户端已经实现了基本的功能,但为了提升用户体验和系统的健壮性,还可以进行一些优化。
1. 用户界面状态管理
根据连接状态来启用或禁用相关控件,避免用户在未连接时进行无效操作。例如,在连接成功前禁用“发送”按钮,连接成功后启用。
Private Sub OnSocketConnectCompleted(ByVal sender As Object, ByVal e As SocketAsyncEventArgs)
If Not socket.Connected Then
AddMessage("Connection failed.")
cmdSend.IsEnabled = False
Return
End If
AddMessage("Connected to server.")
cmdSend.IsEnabled = True
' Messages can be a maximum of 1024 bytes.
Dim response(1023) As Byte
e.SetBuffer(response, 0, response.Length)
RemoveHandler e.Completed, AddressOf OnSocketConnectCompleted
AddHandler e.Completed, AddressOf OnSocketReceive
' Listen for messages.
socket.ReceiveAsync(e)
End Sub
2. 应用程序关闭处理
在应用程序关闭时,需要礼貌地断开与服务器的连接,避免服务器出现异常。可以在应用程序关闭事件中添加相应的处理代码。
Private Sub Application_Exit(ByVal sender As Object, ByVal e As EventArgs)
If (socket IsNot Nothing) AndAlso (socket.Connected) Then
Try
socket.Close()
Catch err As Exception
AddMessage("ERROR: " & err.Message)
End Try
End If
End Sub
3. 消息长度限制
为了防止潜在的错误,需要在用户输入消息时进行长度限制。可以设置文本框的
MaxLength
属性。
<TextBox x:Name="txtMessage" MaxLength="1024" />
本地连接拓展
本地连接模型虽然简单,但也可以进行一些拓展,以满足更复杂的需求。
1. 多对多通信
目前的本地连接示例是单向通信,要实现多对多通信,每个应用程序都需要同时作为发送者和接收者。可以在一个应用程序中同时创建
LocalMessageSender
和
LocalMessageReceiver
对象。
Private messageSender As New LocalMessageSender("MultiReceiver")
Private receiver As New LocalMessageReceiver("MultiReceiver")
Private Sub Page_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
AddHandler receiver.MessageReceived, AddressOf receiver_MessageReceived
receiver.Listen()
End Sub
Private Sub txt_KeyUp(ByVal sender As Object, ByVal e As KeyEventArgs)
messageSender.SendAsync(txt.Text)
End Sub
Private Sub receiver_MessageReceived(ByVal sender As Object, ByVal e As MessageReceivedEventArgs)
lblDisplay.Text = "Received message: """ & e.Message & """"
End Sub
2. 消息确认机制
由于本地连接是“发送即忘”的系统,发送者无法知道消息是否被接收。可以通过在消息内容中添加特定标识,接收者收到消息后发送确认消息,实现消息确认机制。
' 发送消息时添加标识
Private Sub txt_KeyUp(ByVal sender As Object, ByVal e As KeyEventArgs)
Dim messageWithFlag = "MSG:" & txt.Text
messageSender.SendAsync(messageWithFlag)
End Sub
' 接收消息并处理确认
Private Sub receiver_MessageReceived(ByVal sender As Object, ByVal e As MessageReceivedEventArgs)
Dim message = e.Message
If message.StartsWith("MSG:") Then
' 发送确认消息
Dim confirmMessage = "ACK:" & message.Substring(4)
messageSender.SendAsync(confirmMessage)
lblDisplay.Text = "Received message: """ & message.Substring(4) & """"
ElseIf message.StartsWith("ACK:") Then
lblDisplay.Text = "Message confirmed: """ & message.Substring(4) & """"
End If
End Sub
流程图
graph TD;
A[应用程序启动] --> B[初始化消息客户端和本地连接对象];
B --> C[尝试连接服务器];
C --> D{连接成功?};
D -- 是 --> E[启用发送按钮,开始接收消息];
D -- 否 --> F[显示连接失败信息,禁用发送按钮];
E --> G[用户输入消息并发送];
G --> H[检查连接状态];
H -- 已连接 --> I[发送消息并等待确认];
I --> J{收到确认?};
J -- 是 --> K[显示消息已确认];
J -- 否 --> L[重新发送消息];
H -- 未连接 --> M[显示未连接错误信息];
E --> N[监听本地连接消息];
N --> O{收到本地消息?};
O -- 是 --> P[处理消息并发送确认];
O -- 否 --> N;
P --> N;
K --> E;
L --> I;
表格
| 优化拓展点 | 实现方式 |
|---|---|
| 消息客户端用户界面状态管理 | 根据连接状态启用或禁用“发送”按钮 |
| 消息客户端应用程序关闭处理 | 在应用程序关闭事件中关闭套接字连接 |
| 消息客户端消息长度限制 |
设置文本框的
MaxLength
属性
|
| 本地连接多对多通信 |
每个应用程序同时创建
LocalMessageSender
和
LocalMessageReceiver
对象
|
| 本地连接消息确认机制 | 在消息内容中添加标识,接收者发送确认消息 |
总结
通过对Silverlight消息客户端和本地连接模型的深入了解和优化拓展,我们可以开发出功能更强大、用户体验更好的网络通信应用程序。消息客户端通过
Socket
类实现了与服务器的高效通信,而本地连接模型则为同一台计算机上的应用程序交互提供了简单的解决方案。在实际开发中,可以根据具体需求选择合适的通信方式,并结合优化拓展技术,提升应用程序的性能和可靠性。
超级会员免费看
42

被折叠的 条评论
为什么被折叠?



