我正在尝试在C#中使用自托管的websocket。基本上,我当前的测试正在运行,但是当客户端关闭websocket时,代码仍在尝试发送数据。 我想念什么吗?是否有更好的(内置)方法来处理websocket?
(我正在使用.Net Framework 4.8)
using System;
using System.Net.WebSockets;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;
namespace WebSocketTest
{
[ServiceContract]
public interface ITestWebSocketCallback
{
[OperationContract(IsOneWay = true, Action = "*")]
Task SendResult(Message msg);
}
[ServiceContract(CallbackContract = typeof(ITestWebSocketCallback))]
public interface ITestWebSocket
{
[OperationContract(IsOneWay = true, Action = "*")]
Task StartSending(Message msg);
}
public class TestWebSocket : ITestWebSocket
{
public async Task StartSending(Message msg)
{
Console.WriteLine("Started sending");
var callback = OperationContext.Current.GetCallbackChannel<ITestWebSocketCallback>();
try
{
var random = new Random();
var result = 100.00;
while (((IChannel)callback).State == CommunicationState.Opened)
{
await callback.SendResult(CreateMessage($"{result}"));
result += random.NextDouble();
await Task.Delay(1000);
}
Console.WriteLine("Channel closed");
}
catch (WebSocketException wse)
{
Console.WriteLine($"WebSocketException: {wse.Message}");
}
catch (Exception e)
{
Console.WriteLine($"Exception: {e.Message}");
}
Console.WriteLine("Finished sending");
}
Message CreateMessage(string msgText)
{
var msg = ByteStreamMessage.CreateMessage(new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgText)));
msg.Properties["WebSocketMessageProperty"] = new WebSocketMessageProperty
{
MessageType = WebSocketMessageType.Text
};
return msg;
}
}
static class Program
{
static void Main(string[] args)
{
var baseAddress = new Uri("http://localhost:8080/TestWS");
// Create the ServiceHost.
var _host = new ServiceHost(typeof(TestWebSocket), baseAddress);
//// Enable metadata publishing.
var behaviour = new ServiceMetadataBehavior();
behaviour.HttpGetEnabled = true;
behaviour.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
_host.Description.Behaviors.Add(behaviour);
// Create WebSocket
var binding = new CustomBinding();
binding.Elements.Add(new ByteStreamMessageEncodingBindingElement());
var transport = new HttpTransportBindingElement();
transport.WebSocketSettings.TransportUsage = WebSocketTransportUsage.Always;
transport.WebSocketSettings.CreateNotificationOnConnection = true;
binding.Elements.Add(transport);
_host.AddServiceEndpoint(typeof(ITestWebSocket), binding, "");
// Open the ServiceHost to start listening for messages.
Console.WriteLine("Opening websocket...");
try
{
_host.Open();
Console.WriteLine("Opened!");
Console.WriteLine(baseAddress);
}
catch (Exception e)
{
Console.WriteLine($"Cannot open: {e.Message}");
throw;
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
}
除了输出类似于:
Started sending
Channel closed
Finished sending
但是我得到了
Started sending
WebSocketException
Finished sending
答案 0 :(得分:0)
据我所知,这是不可能的。如官方文档中所述(由于WCF通过使用websocket协议实现双工通信,因此双工通信等于websocket)。
双工模型不会自动检测服务或客户端的时间 关闭其频道。因此,如果客户端意外终止,则默认情况下 不会通知该服务,或者如果服务意外 终止,不会通知客户端。如果您使用的服务 断开连接后,将引发CommunicationException异常。 客户端和服务可以实现自己的协议以通知每个 其他,如果他们选择的话。有关错误处理的更多信息,请参见 WCF错误处理
https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/duplex-services
在我看来,我们可以发送一个心跳包来证明客户端处于活动状态,或者可以定义和实现另一个服务合同,或者在OperationContext等下面使用。
OperationContext.Current.Channel.Faulted += delegate
{
Console.WriteLine("");
};