zoukankan      html  css  js  c++  java
  • C# winform websocket学习笔记(三)winform客户端

    1 功能设计

    连接服务端地址;

    从服务端自动获取a,b的值;

    通过向服务端发送数据,实现所有客户端同步更新;

    将使用中一些信息显示出来。

    2 界面设计

    3 代码实现

    3.1 命名空间与引用

    using System.Threading;//CancellationToken
    using System.Net.WebSockets;
    using Newtonsoft.Json;

    3.2 数据格式

    先还是约定好数据格式,通过json形式传输。

    /// <summary>
            /// //以dictionary将数据的键值对匹配,然后进行json序列化,避免定义类的麻烦。
            /// </summary>
            /// <param name="valueA"></param>
            /// <param name="valueB"></param>
            /// <returns></returns>
            public static string SerializeJson(string valueA, string valueB)
            {
                if (valueA.Length == 0) { valueA = "-"; }
                if (valueB.Length == 0) { valueB = "-"; }
                //以dictionary将数据的键值对匹配,然后进行json序列化,避免定义类的麻烦。参考:https://www.cnblogs.com/kevinWu7/p/10163455.html
                Dictionary<string, string> dic = new Dictionary<string, string>(){
                    { "a",valueA },
                    { "b",valueB }
                };
                string Jsondata = JsonConvert.SerializeObject(dic);
                return Jsondata;
            }
    View Code
    //用于json反序列化获取实体
        public class TestValue
        {
            public string a { get; set; }
            public string b { get; set; }
        }

    3.3 连接服务端

    先实例化一个ClientWebSocket对象,由于之后别的关闭连接事件之类的要用到,所以设为静态。

            static ClientWebSocket client = new ClientWebSocket();//实例化客户端对象

    然后开启连接

    //开启连接
            private void btnStartConnect_Click(object sender, EventArgs e)
            {
                if (txtServerAddress.Enabled == true)
                {
                    MessageBox.Show("请先确认地址");
                    return;
                }
                
                string ServerAddress = txtServerAddress.Text;
                //如果已经连上了服务端,想要再次进行连接,需要进行判断,关闭当前连接后才能进行
                if (client.State == WebSocketState.Open)
                {
                    MessageBox.Show("当前client对象连接状态为open,若要重新连接,请先关闭当前连接");
                    return;
                }
                
                try
                {
                    client = new ClientWebSocket();//这一句不要进行状态判断,因为除了Open和Closed,还有Abort等好几种状态。干脆每次连接重新初始化。
                    client.ConnectAsync(new Uri(ServerAddress), CancellationToken.None).Wait();
                    txtInfo.AppendText("开启了连接" + DateTime.Now.ToString() + "
    ");
                }
                catch (Exception ex)
                {
                    txtInfo.AppendText(ex.ToString()+ DateTime.Now.ToString() + "
    ");
                    MessageBox.Show("连接出现问题,请检查网络是否通畅,地址是否正确,服务端是否开启");
                    return;
                }
                finally
                {
                    lblState.Text = client.State.ToString();
                }
    
                StartReceiving(client);            
            }
    View Code

    由于client之前可能开关失败过或者什么的,会导致对象被dispose,直接连接会导致报“对象已经被释放”的错,因此此处每次进行异步连接的时候,都将对象初始化一下。

    之前这个问题困扰了我,此处感谢CSDN论坛热心大佬 wanghui0380 的帮助。

    3.4 接收数据

    先判断连接状态正常,之后保持循环异步读取,通过client.ReceiveAsync()进行接收,获取到数据之后,字节数组转为字符串,由于服务端以json字符串发来,需要进行反序列化,使用Newtonsoft.Json这个工具的方法,最终获取到a,b的值,将其显示到文本框。

            /// <summary>
            /// 异步接收服务端数据,获取json数据后反序列化,然后显示到文本框控件中
            /// </summary>
            /// <param name="client"></param>
            private async void StartReceiving(ClientWebSocket client)
            {
                if (client.State != WebSocketState.Open)//正常来说进入到此方法的状态都为Open
                {
                    lblState.Text = client.State.ToString();
                    MessageBox.Show("StartReceiving方法:连接状态异常,请尝试重新连接");
                    return;
                }
                try//有可能中途连接断开
                {
                    while (true)
                    {
                        var array = new byte[2048];
                        if (!((client.State == WebSocketState.Open) || (client.State == WebSocketState.CloseSent)))
                        {
                            //接收消息的有效状态是Open和CloseSent,如果不是这两种状态,则退出。
                            //主动退出也会影响异步线程的接收,因此先进行判断
                            lblState.Text="Closed";
                            txtInfo.AppendText("StartReceiving方法:连接状态异常,退出循环接收,请检查" + DateTime.Now.ToString() + "
    ");
                            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反序列化。参考:https://www.cnblogs.com/yinmu/p/12160343.html
                                TestValue tv = JsonConvert.DeserializeObject<TestValue>(jsonmsg);
                                //将收到的a,b的值显示到文本框
                                if (tv != null)
                                {
                                    string valueA = string.Empty, valueB = string.Empty;
                                    if (tv.a != null && tv.a.Length > 0) { valueA = tv.a; }
                                    if (tv.a != null && tv.b.Length > 0) { valueB = tv.b; }
                                    txtValueA.Text = valueA;
                                    txtValueB.Text = valueB;                            
                                }
                            }
                            catch (Exception ex)
                            { 
                                //如果json反序列化出了问题
                                txtInfo.AppendText(ex.ToString() + DateTime.Now.ToString() + "
    ");//将错误类型显示出来
                                txtInfo.AppendText(jsonmsg+"
    ");//将收到的原始字符串显示出来
                            }
                        }
                    }
                }
                catch (Exception ex)//看看什么类型的错误
                {
                    lblState.Text = client.State.ToString();
                    //MessageBox.Show(ex.ToString());//暂且注释,弹出消息框影响观感
                    if (ex.GetType().ToString() == "System.Net.WebSockets.WebSocketException" && client.State != WebSocketState.Open)
                    {
                        //客户端关闭时会抛出此错误
                        txtInfo.AppendText("连接被关闭,请检查网络或服务器"+ DateTime.Now.ToString() + "
    ");
                    }
                    else
                    {
                        txtInfo.AppendText(ex.ToString() + DateTime.Now.ToString() + "
    ");
                    }
                }
                //finally
                //{
                //    if (client != null)
                //    {
                //        client.Dispose();
                //    }
                //}
                
            }
    View Code

    3.5 发送数据

    这里很简单,将a,b的值包装成json字符串。判断连接状态后,用client.SendAsync()方法即可。

    //向服务端发送数据
            private void btnSendMsg_Click(object sender, EventArgs e)
            {
                if (txtServerAddress.Enabled == true)
                {
                    MessageBox.Show("请先确认地址");
                    return;
                }
                string valueA = string.Empty, valueB = string.Empty;
                valueA = txtValueA.Text;
                valueB = txtValueB.Text;
                string jsondata = SerializeJson(valueA, valueB);
    
                var array = new ArraySegment<byte>(Encoding.UTF8.GetBytes(jsondata));
                //此处需要捕捉异常,连接是否通畅?
                try
                {
                    if (client.State == WebSocketState.Open)//连通状态才允许发送
                    {
                        client.SendAsync(array, WebSocketMessageType.Text, true, CancellationToken.None);   
                    }
                    else
                    {
                        MessageBox.Show("连接状态异常,请尝试重新连接");
                    }
                }
                catch (Exception ex)
                {
                    txtInfo.AppendText(ex.ToString() + DateTime.Now.ToString() + "
    ");
                    return;
                }
                finally
                {
                    lblState.Text = client.State.ToString();
                }
                            
            }
    View Code

    winform客户端部分就到这里,下一篇是HTML页的客户端。

    整个项目源码可以到上一篇服务端末尾下载。

  • 相关阅读:
    IO 模型
    进程、线程、锁
    用多线程,实现并发,TCP
    同步锁(互斥锁),GIL锁(解释器层面的锁),死锁与递归锁
    Java项目中的常用的异常2
    JAVA项目中的常用的异常处理情况1
    添加学生信息web界面连接数据库
    jdbc下载路径
    添加学生信息 web界面 并且连接数据库
    正则表达式
  • 原文地址:https://www.cnblogs.com/ygxddxc/p/13215531.html
Copyright © 2011-2022 走看看