zoukankan      html  css  js  c++  java
  • Socket 两平台互相 通信 .NET

      两个平台互相通信,对方发送数据过来,我方接收数据,对数据进行处理后发送结果给对方,对方进行相应的操作。

      首页,我方开启服务监听:

                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress address = IPAddress.Parse(txtIP.Text.Trim());
                IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
                socket.Bind(endPoint);
                socket.Listen(12);
                Socket clientReqSocket = socket.Accept();
                byte[] arrMsg = new byte[1024 * 2];          
                int arrLen = clientReqSocket.Receive(arrMsg);

      提取实际有效数据:

                byte[] arrNew = new byte[arrLen];        
                Buffer.BlockCopy(arrMsg, 0, arrNew, 0, arrLen);

      在对接收到的数据arrNew进行业务处理之后,将结果arrResult返回给对方,最后关闭连接:

                clientReqSocket.Send(arrResult);
                clientReqSocket.Close();    
           socket.Close();

      对上面代码进行讲解:首先,socket.Accept();这个方法,服务会一直停留在这个方法上面,等待客户端的连接,一有客户端连接上来,才会继续执行下面的代码。如果没有客户端来连接服务,程序将会一直停留在这个地方,会出现“假死”的现象。其次,上面的代码示例只能处理一个客户端的连接请求,请求处理完成后,就会关闭连接。服务端应该是一个永不会停止的程序,能够一直监听客户端的请求,并对其进行处理和回馈。

      所以对上面的问题进行说明,首先使用线程,开启服务后,服务端处理监听状态,当有客户端连接请求上来后,为该客户端连接新创建一个线程,专门来处理该客户端的请求操作。当有多个客户端连接上来后,服务会为每个客户端都新创建线程来处理。这样服务可以继续监听其他客户端的连接请求,一边又可以对已连接上来的客户端进行响应处理。其次,要服务队能够永远的监听客户端的连接请求,就必须让服务端在处理完一个客户端的连接请求后,能够继续调用socket.Accept()来监听连接请求,这里使用while(true){}无限循环来实现。

            bool isListener = true;
    
            /// <summary>
            /// 监听远程数据
            /// </summary>
            void startListen()
            {
                while (isListener)
                {
                    try
                    {
                        Socket clientReqSocket = socket.Accept();
                        byte[] arrMsg = new byte[1024 * 2];
                        int arrLen = clientReqSocket.Receive(arrMsg);
    
                        byte[] arrNew = new byte[arrLen];        
                        Buffer.BlockCopy(arrMsg, 0, arrNew, 0, arrLen);
                
                     //进行业务处理后(此处省略部分代码),返回arrResult。
                        clientReqSocket.Send(arrResult);
                        clientReqSocket.Close();    
                    }
                    catch (Exception ex)
                    {
                        isListener = false;
                    }
                }
            }

      由于本次需求上只有一个客户端,所以这次没有采用多线程的方式。只是在主线程上,新建一条线程专门用来监听和处理客户端的请求操作,这样主线程还可以继续执行它的任务,程序也不会出现“假死”的状态。

      当然,对于客户端发送过来的数据,服务端要能进行识别判断,提取有效数据。所以在本次双方通信过程中,对数据的格式进行了约定,只有遵循了格式的数据才会进行处理解析和响应。接口协议定义如下表所示(数据协议XML结构定义省略):

    通讯数据包结构定义如表下:
    包头标记 总长 消息类型 XML流长度 XML格式数据 包尾标记
    4B 4B 1B 4B   2B
    数据包内各项目定义说明如下表:
    序号 项目名称 取值 说明
    1  包头 0xE1 0x2B 0xD3 0x78 取固定值
    2 总长   4个字节(包括包头包尾的长度)
    3 消息类型 0x21 或者 0x22 用于区别数据包的类型
    4 XML流长度   XML格式数据的长度(4bytes)
    5 XML格式数据   为所传递的XML报文
    6 包尾 0xFF 0xFF 取固定值
    数据包协议类型说明如下表:
    消息号 说明 XML格式
    0x21 表示客户端向服务端发送数据 XMLInfoSed
    0x22 表示服务端向客户端发送数据 XMLInfoReq

       定义好通信协议之后,Socket通信就需要遵循这个协议,服务端和客户端都只接收该遵循该协议的报文和发送该格式的报文。

            bool isListener = true;
    
            /// <summary>
            /// 监听远程数据
            /// </summary>
            void startListen()
            {
                while (isListener)
                {
                    try
                    {
                        Socket clientReqSocket = socket.Accept();
                        byte[] arrMsg = new byte[1024 * 2];
                        int  arrLen = clientReqSocket.Receive(arrMsg);
    
                        if (arrLen != 0)
                        {
                            byte[] arrNew;
                           
                            if (arrMsg[8] == 0x21)//接收数据
                            {
                                try
                                {
                                    arrNew = new byte[arrLen];
                                    //提取XML数据部分 数据包定义:头13字节 XML数据 尾2字节
                                    Buffer.BlockCopy(arrMsg, 13, arrNew, 0, arrLen - 15);
                       string msg = Encoding.GetEncoding("GB2312").GetString(arrNew);
                                    XmlDocument xmlDom = new XmlDocument();
                                    //加载XML数据
                                    xmlDom.LoadXml(msg);
                                    //解析XML数据,将XML数据发送给后台系统进行业务逻辑处理(此处省略)
                                    clientReqSocket.Close(); 
                                }
                                catch (Exception ex)
                                {
                                    clientReqSocket.Close();
                                    continue;//服务继续监听
                                }
                            } else if (arrMsg[8] == 0x22)//接收发送数据
                            {
                                try
                                {
                                    byte[] arrNew = new byte[13];
                                    //包头标记 固定值 (4B)
                                    arrNew[0] = 0xE1;
                                    arrNew[1] = 0x2B;
                                    arrNew[2] = 0xD3;
                                    arrNew[3] = 0x78;
                                    //消息类型 0x22 表示为服务端向客户端发送数据 (1B)
                                    arrNew[8] = 0x22;
    
                                    byte[] xmlArr = new byte[arrLen];
                                    Buffer.BlockCopy(arrMsg, 0, xmlArr, 0, arrLen);
    
                                    string msg = Encoding.GetEncoding("GB2312").GetString(xmlArr);
    
                                    string hexLength = String.Format("{0:X8}", msg.Length);
    
                                    //XML流长度 需要统计 (4B)
                                    arrNew[10] = Convert.ToByte(hexLength.Substring(6, 2), 16);
                                    arrNew[11] = Convert.ToByte(hexLength.Substring(4, 2), 16);
                                    arrNew[12] = Convert.ToByte(hexLength.Substring(2, 2), 16);
                                    arrNew[13] = Convert.ToByte(hexLength.Substring(0, 2), 16);
    
                                    //包首部 + XML数据长度 + 包尾部
                                    int dataLen = arrNew.Length + xmlArr.Length + 2;
    
                                    string dataHexLen = String.Format("{0:X8}", dataLen);
                                    //总长 (包括包头包尾长度) 需要统计 4(B)
                                    arrNew[4] = Convert.ToByte(dataHexLen.Substring(6, 2), 16);
                                    arrNew[5] = Convert.ToByte(dataHexLen.Substring(4, 2), 16);
                                    arrNew[6] = Convert.ToByte(dataHexLen.Substring(2, 2), 16);
                                    arrNew[7] = Convert.ToByte(dataHexLen.Substring(0, 2), 16);
    
                                    byte[] newArr = new byte[dataLen];
                                    Buffer.BlockCopy(arrNew, 0, newArr, 0, arrNew.Length);
                                    Buffer.BlockCopy(arr, 0, newArr, arrNew.Length, arr.Length);
                                    newArr[dataLen - 2] = 0xFF;
                                    newArr[dataLen - 1] = 0xFF;
    
                                    //向客户端发送数据
                                    Socket toclientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                                    IPAddress address = IPAddress.Parse(txtCIP.Text.Trim());
                                    IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtCPort.Text.Trim()));
                                    toclientSocket.Connect(endPoint);
                                    toclientSocket.Send(newArr);
                                   
                                    clientReqSocket.Send(new byte[1] { 0 });//发送成功
    
                                    toclientSocket.Close();
                         clientReqSocket.Close();
                                }
                                catch (Exception ex)
                                {
                                     clientReqSocket.Send(new byte[1] { 4 });//发送数据失败
    clientReqSocket.Close(); continue; } } } } catch (Exception ex) { isListener = false; } } }

       在这里本服务成为一个类似中转站的机器,客户端向本服务发送数据,本服务接收数据,对数据进行解析,解析完成后将数据交给后台系统,后台系统对数据进行业务逻辑处理后,将结果数据发送给本服务,然后本服务将最后结果数据发送给客户端。原本不需要本服务中间这一环节,客户端和后台系统可以直接进行通信交互,但是因为业务要求,所以必须要有本服务这一中间环节。

      对上面代码进行说明:首页本服务要先判断接收到的数据为客户端发送来的数据,还是后台系统需要向客户端发送的数据。根据通信数据包结构定义,消息类型占1个字节,前面有包头4字节和总长4字节共8个字节,所以消息类型在第9个字节的位置。对接收到的数据arrMsg[8]第9个字节进行判断,如果arrMsg[8] = 0x22表示为客户端发送来的数据,客户端发送来的数据,本服务需要提取XML数据部分,然后对XML数据进行解析,将后台服务需要的数据发送给后台。

      Buffer.BlockCopy(arrMsg, 13, arrNew, 0, arrLen - 15);去除头13个字节和尾2个字节,提取XML数据部分。

      如果arrMsg[8] == 0x22表示后台系统要向客户端发送的数据,接收到后台系统发送过来的数据,首先要对数据进行封装,将数据组装成为约定好的XML结构(本服务接收到的数据就为XML数据),然后将该XML数据添加包头包尾,重新封装成为客户端能够识别的数据结构。将数据进行重新封装后发送给客户端,并且通知后台系统发送结果状态。

      在这里主要是想跟大家分享,在网络通信过程中,对于有通信接口格式定义的该如何进行交互。

  • 相关阅读:
    在 ASP.NET 2.0 中上载文件
    ASP.NET(C#)FileUpload实现上传限定类型和大小的文件到服务器<from Copying>
    aspnetupload 上传组件在VS2008中使用详细说明
    基于asp.net 的文件上传和下载~~~转
    设置竖直的分割符【使用div】 (根据屏幕的大小自适应)
    分隔线
    UGUI事件系统
    U3D音频系统
    Unity启动事件-监听:InitializeOnLoad
    VS生成桌面应用程序
  • 原文地址:https://www.cnblogs.com/hundansrs/p/3350749.html
Copyright © 2011-2022 走看看