websocket 介绍
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
在这里插入图片描述
废话不多说下面上代码
client定义
首先定义一个client:
private ClientWebSocket client = new ClientWebSocket();//实例化客户端对象
定义几个委托用来更新日志,状态,返回结果
public Action<string> ActionUpdateString;//更新运行日志
public Action<string> ActionUpdateStatus;//更新client状态
public Action<RemoteJsonRecie> ActionUpdateResult;//上传收到的结果
client连接
public void StartConnect(string ServerAddress)
{
//如果已经连上了服务端,想要再次进行连接,需要进行判断,关闭当前连接后才能进行
if (client.State == WebSocketState.Open)
{
if(ActionUpdateString != null)ActionUpdateString("当前client对象连接状态为open,若要重新连接,请先关闭当前连接");
return;
}
try
{
client = new ClientWebSocket();//这一句不要进行状态判断,因为除了Open和Closed,还有Abort等好几种状态。干脆每次连接重新初始化。
client.ConnectAsync(new Uri(ServerAddress), CancellationToken.None).Wait();
if(ActionUpdateString!=null)ActionUpdateString("开启了连接" + DateTime.Now.ToString() + "\n");
}
catch (Exception ex)
{
if (ActionUpdateString != null) ActionUpdateString(ex.ToString() + DateTime.Now.ToString() + "\n");
if (ActionUpdateString != null) ActionUpdateString("连接出现问题,请检查网络是否通畅,地址是否正确,服务端是否开启");
return;
}
finally
{
if (ActionUpdateStatus != null) ActionUpdateStatus( client.State.ToString());
}
//开启receive线程
StartReceiving(client);
}
client 发送函数
//此处的RemoteJsonSend 是自己更具需要定义的一个序列化的类
public void SendMsg(RemoteJsonSend rmj)
{
string sendjsondata = JsonConvert.SerializeObject(rmj);
var array = new ArraySegment<byte>(Encoding.UTF8.GetBytes(sendjsondata));
//此处需要捕捉异常,连接是否通畅?
try
{
if (client.State == WebSocketState.Open)//连通状态才允许发送
{
client.SendAsync(array, WebSocketMessageType.Text, true, CancellationToken.None);
}
else
{
if (ActionUpdateString != null) ActionUpdateString("连接状态异常,请尝试重新连接");
}
}
catch (Exception ex)
{
if (ActionUpdateString != null) ActionUpdateString(ex.ToString() + DateTime.Now.ToString() + "\n");
return;
}
finally
{
if (ActionUpdateStatus != null) ActionUpdateStatus(client.State.ToString());
}
}
client异步接收函数
/// <summary>
/// 异步接收服务端数据,获取json数据后反序列化,然后显示到文本框控件中
/// </summary>
/// <param name="client"></param>
public async void StartReceiving(ClientWebSocket client)
{
if (client.State != WebSocketState.Open)//正常来说进入到此方法的状态都为Open
{
if (ActionUpdateStatus != null) ActionUpdateStatus(client.State.ToString());
if (ActionUpdateString != null) ActionUpdateString("StartReceiving方法:连接状态异常,请尝试重新连接");
return;
}
try//有可能中途连接断开
{
while (true)
{
var array = new byte[2048];
if (!((client.State == WebSocketState.Open) || (client.State == WebSocketState.CloseSent)))
{
//接收消息的有效状态是Open和CloseSent,如果不是这两种状态,则退出。
//主动退出也会影响异步线程的接收,因此先进行判断
if (ActionUpdateStatus != null) ActionUpdateStatus ("Closed");
if (ActionUpdateString != null) ActionUpdateString("StartReceiving方法:连接状态异常,退出循环接收,请检查" + DateTime.Now.ToString() + "\n");
return;
}
var result = await client.ReceiveAsync(new ArraySegment<byte>(array), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Text)
{
//获取字节数组并转为字符串,此字符串应为json类型,需要反序列化
string jsonmsg = Encoding.UTF8.GetString(array, 0, result.Count);
try//将反序列化内容放入try中,避免无法匹配、内容为空等可能报错的地方
{
//将转换后的字符串内容进行json反序列化。
RemoteJsonRecie re = JsonConvert.DeserializeObject<RemoteJsonRecie>(jsonmsg);
if (re != null)
{
if (ActionUpdateResult != null)
ActionUpdateResult(re);
}
}
catch (Exception ex)
{
//如果json反序列化出了问题
if (ActionUpdateString != null) ActionUpdateString(ex.ToString() + DateTime.Now.ToString() + "\n");//将错误类型显示出来
if (ActionUpdateString != null) ActionUpdateString(jsonmsg + "\n");//将收到的原始字符串显示出来
}
}
}
}
catch (Exception ex)//看看什么类型的错误
{
if (ActionUpdateStatus != null) ActionUpdateStatus( client.State.ToString());
//MessageBox.Show(ex.ToString());//暂且注释,弹出消息框影响观感
if (ex.GetType().ToString() == "System.Net.WebSockets.WebSocketException" && client.State != WebSocketState.Open)
{
//客户端关闭时会抛出此错误
if (ActionUpdateString != null) ActionUpdateString("连接被关闭,请检查网络或服务器" + DateTime.Now.ToString() + "\n");
}
else
{
if (ActionUpdateString != null) ActionUpdateString(ex.ToString() + DateTime.Now.ToString() + "\n");
}
}
//finally
//{
// if (client != null)
// {
// client.Dispose();
// }
//}
}
client 关闭
public void CloseConnection()
{
if (client.State == WebSocketState.Open)
{
try
{
client.CloseAsync(WebSocketCloseStatus.Empty, string.Empty, CancellationToken.None);
client.Dispose();
if (ActionUpdateString != null) ActionUpdateString("主动关闭了连接" + DateTime.Now.ToString() + "\n");
if (ActionUpdateStatus != null) ActionUpdateStatus("Closed");
}
catch (Exception ex)
{
if (ActionUpdateString != null) ActionUpdateString(ex.ToString() + DateTime.Now.ToString() + "\n");
}
finally
{
if (ActionUpdateStatus != null) ActionUpdateStatus(client.State.ToString());
}
}
}
完整版的代码可点击此处下载WEBSOCKET CLIENT