本位主要记录了奔驰项目中websocket通讯改造遇到的问题。

背景

之前终端与服务器通讯采用的是tcp/ip模式,但甲方对安全性要求极高不开放tcp通讯所需要的端口,无奈之下兄弟们决定采用websocket与终端交互,这样可以使用已有的80端口。

改造

原先的Tcp客户端结构如下(部分):

    public class TcpStocketClient
    {
    	///<summary>
        /// 客户端socket对象
        /// </summary>
        public Socket Tcpsocket;

        /// <summary>
        /// 服务线程(负责socket接收)
        /// </summary>
        public Thread processor;

        public bool Start()
        { try
            {
        	Clear();
            Tcpsocket = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);
            IPAddress ip = IPAddress.Parse(this.IP);
            IPEndPoint ipep = new IPEndPoint(ip, this.Port);//IP和端口
            //Tcpsocket.Connect(ipep);
            IAsyncResult result = Tcpsocket.BeginConnect(ip, Port, null, null);
            result.AsyncWaitHandle.WaitOne(2000, true);
            if (!result.IsCompleted)
            {
                return false;
            }

            LastRecTime = DateTime.Now;
            processor = new Thread(new ThreadStart(Communication));
            processor.SetApartmentState(ApartmentState.STA);
            processor.IsBackground = true;
            processor.Start();
            return true;
           }
            catch (Exception ex)
            {
                this.isConnect = false;
                return false;
            }
            finally
            {
                this.communicationobserve_timer.Enabled = true;
            }
        }

        private void Communication()
        {
            try
            {
                while (true)
                {
                	 //已经精简
                	 int lengh = this.Tcpsocket.Receive(buffertemp);

                }
            }
            catch (Exception ex)
            {
                this.isConnect = false;
            }
    }

上面代码主要使用了Tcpsocket.BeginConnect() 和Tcpsocket.Receive(); 经过一番调研 发现微软提供了using System.Net.WebSockets.ClientWebSocket类,下面进行是最小变动改造:

public class TcpWebSocketClient
    {
    	 ///<summary>
        /// 客户端socket对象
        /// </summary>
        public ClientWebSocket Wbsocket;

        /// <summary>
        /// 取消编辑
        /// </summary>
        CancellationToken cancellation = new CancellationToken();

        /// <summary>
        /// 服务线程(负责socket接收)
        /// </summary>
        public Thread processor;


        /// <summary>
        /// 启动通讯
        /// </summary>
        public bool Start()
        {
            try
            {
                Clear();
                
                string url = string.Format("ws://{0}:{1}/cdmsA/webSocket?sn={2}", IP, Port,SN);
                Wbsocket = new System.Net.WebSockets.Managed.ClientWebSocket();
                IAsyncResult result = Wbsocket.ConnectAsync(new Uri(url), cancellation);
                result.AsyncWaitHandle.WaitOne(2000, true);
                if (!result.IsCompleted)
                {
                    LogUtil.LogHelper.NetLog("websocket连接超时");
                    return false;
                }

                LastRecTime = DateTime.Now;
                processor = new Thread(new ThreadStart(Communication));
                processor.SetApartmentState(ApartmentState.STA);
                processor.IsBackground = true;
                processor.Start();
                return true;
            }
            catch (Exception ex)
            {
                this.isConnect = false;
                LogUtil.LogHelper.ErrorForNet(ex);
                return false;
            }
            finally
            {
                this.communicationobserve_timer.Enabled = true;
            }
        }


         /// <summary>
        /// 接收服务发过来的数据
        /// </summary>
        private async void Communication()
        {
            try
            {
                while (true)
                {
                	 //  int lengh = this.Tcpsocket.Receive(buffertemp);
                        WebSocketReceiveResult r = await Wbsocket.ReceiveAsync(new ArraySegment<byte>(buffertemp), new CancellationToken());//接受数据
                        if (r.Count <= 0)
                        {

                        }
                }
 			}
            catch (Exception ex)
            {
                this.isConnect = false;
            }
    }

websocket连接地址的格式为 “ws:+url” 同过上面代码对比可以发现微软提供websocket框架提供了Wbsocket.ConnectAsync()和Wbsocket.ReceiveAsync()对应于tcp方式的Tcpsocket.BeginConnect() 和Tcpsocket.Receive();通过以上两处修改,可以实现websocket与服务器交互。

Https

随着甲方需求的深入,服务器要求采用https协议 与之相应的websocket也需要调整:

 string url = string.Format("ws://{0}:{1}/cdmsA/webSocket?sn={2}", IP, Port,SN);
                if (ConfigurationManager.AppSettings["IsHttps"] == "1")
                {
                    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                    ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;// SecurityProtocolType.Tls1.2; 
                    ServicePointManager.CheckCertificateRevocationList = true;
                    ServicePointManager.DefaultConnectionLimit = 100;
                    ServicePointManager.Expect100Continue = false;
                    url = string.Format("wss://{0}:{1}/cdmsA/webSocket?sn={2}", IP, Port,SN);
                }

 	    private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受  
        }

与http方式相比,https需要设置证书。

Win7下的问题

由于开发部门都是win10的系统,测试以上代码都是没有问题的,某天客户问道win7系统是不是连不上服务器,当时也没多想,毕竟使用的都是微软框架下的东西。后来找到win7机器测试了下果然爆出异常,查了相关资料发现微软官方文档明确说明了websocket不支持win7….. 后背一阵发凉。最后通过如下方法解决: 引用:System.Net.WebSockets.Client.Managed websocket对象采用该库对象

///<summary>
/// 客户端socket对象
/// </summary>
public System.Net.WebSockets.Managed.ClientWebSocket Wbsocket;