C#与其他系统通信接口总结

  大家应该都知道,在与其他系统交互的时候,通常有两种方式,webservice和socket通信。

  这个接口项目我使用的是socket通信方式,内容以xml方式包装,按照约定的格式收发。socket通信一般用到的为TCP和UDP两种,具体区别以及它们的优缺点可以参考资料http://jingyan.baidu.com/article/6dad5075df3452a123e36ecb.html,这里我采用TCP方式。

  在C#中可以使用.net提供的TcpListener建立服务端,TcpClient建立客户端。正常情况,因为TCP是全双工,只要作为服务端或者客户端连接上就可以收发信息。但是这个项目中由于第三方系统历史遗留的问题,我们同时建立了服务端和客户端,服务端用来收消息,客户端用来发消息。

  背景介绍完毕,下面上代码

  服务端代码

  

 /// <summary>
    /// 服务端类,用于接收客户端消息
    /// </summary>
    class TcpListen
    {
        /// <summary>
        /// 连接上的客户端集合
        /// </summary>
        List<RemoteClient> remoteClientList = new List<RemoteClient>();
        /// <summary>
        /// 服务端监听对象
        /// </summary>
        private TcpListener myListener;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="localIP"></param>
        /// <param name="port"></param>
        public TcpListen(string localIP,int port)
        {
            /// <summary>使用的本机IP地址</summary>
            IPAddress localAddress = IPAddress.Parse(localIP);
            myListener = new TcpListener(localAddress, port);
            myListener.Start();
            //创建一个线程监听客户端连接请求
            Thread myThread = new Thread(ListenClientConnect);
            myThread.Start();
        }

        /// <summary>
        /// 接收客户端连接
        /// </summary>
        private void ListenClientConnect()
        {
            while (true)
            {
                TcpClient newClient = null;
                try
                {
                    newClient = myListener.AcceptTcpClient();
                }
                catch
                {
                    //当退出时AcceptTcpClient()会产生异常
                    //因此可以利用此异常退出循环
                    break;
                }
                //每接受一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息
                RemoteClient user = new RemoteClient(newClient);
                remoteClientList.Add(user);
                Thread threadReceive = new Thread(ReceiveData);
                threadReceive.Start(user);

            }
        }       

        /// <summary>
        /// 处理接收的客户端数据
        /// </summary>
        /// <param name="userState">客户端信息</param>
        private void ReceiveData(object userState)
        {
            RemoteClient user = userState as RemoteClient;
            TcpClient client = user.client;
            while (true)
            {
                byte[] BytesLenth = null;
                byte[] BytesContent = null;
                try
                {
                    if (user == null || user.br == null || user.client.Connected == false)
                    {
                        break;
                    }
                    BytesLenth = user.br.ReadBytes(2);
                    int lenth = BitConverter.ToInt16(BytesLenth, 0);
                    BytesContent = user.br.ReadBytes(lenth - 2);
                    string conContent = Encoding.Default.GetString(BytesContent);

                    //如果收到是心跳信息
                    if (conContent == "0000")
                    {
                         ClassVar.frmMain.timeSpan = 0;
                    }
                    //如果是警情信息则加入到消息队列
                    else
                    {
                        lock (ClassVar.frmMain.lockQue)
                        {
                            ClassVar.frmMain.queueXml.Enqueue(conContent);
                        }
                    }
                }
                catch (Exception ex)
                {
                    RemoveUser(user);
                }
            }
        }

        /// <summary>移除用户</summary>
        /// <param name="user">指定要删除的用户</param>
        private void RemoveUser(RemoteClient remoteClient)
        {
            remoteClientList.Remove(remoteClient);
            remoteClient.Close();
        }
   /// <summary>
    /// 服务端管理远程客户端类
    /// </summary>
    class RemoteClient
    {
        public TcpClient client{get; private set;}
        public BinaryReader br{get; private set;}
        public BinaryWriter bw{get; private set;}
        public string userName {get; set; }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="client"></param>
        public RemoteClient(TcpClient client)
        {
            this.client = client;
            NetworkStream networkStream = client.GetStream();
            br = new BinaryReader(networkStream);
            bw = new BinaryWriter(networkStream);
            this.userName = (client.Client.RemoteEndPoint as IPEndPoint).Address.ToString() + ":"+(client.Client.RemoteEndPoint as IPEndPoint).Port.ToString();
        }
        /// <summary>
        /// 关闭与远程客户端的连接
        /// </summary>
        public void Close()
        {
            br.Close();
            bw.Close();
            client.Close();
        }
    }

客户端

/// <summary>
    /// 客户端类,用来给服务端发送消息
    /// </summary>
    class Client
    {
        #region 变量
        /// <summary>
        /// tcp通信对象
        /// </summary>
        private TcpClient tcpClient;
        /// <summary>
        /// tcp通信中读取数据的对象
        /// </summary>
        private BinaryReader br;
        /// <summary>
        /// tcp通信中写数据的对象
        /// </summary>
        private BinaryWriter bw;
        /// <summary>
        /// 通信的远程服务器ip
        /// </summary>
        private string IP;
        /// <summary>
        /// 通信的远程服务器端口
        /// </summary>
        private int port;

        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="ip">服务器IP</param>
        /// <param name="port">服务器开放的通信端口号</param>
        public Client(string ip,int port)
        {
            this.IP = ip;
            this.port = port;
        }
        #endregion

        // 连接服务器
        /// <summary>
        /// 连接服务器
        /// </summary>
        public void Connect()
        {
            try
            {
                tcpClient = new TcpClient(IP, port);
                //获取网络流
                NetworkStream networkStream = tcpClient.GetStream();
                //将网络流作为二进制读写对象
                br = new BinaryReader(networkStream);
                bw = new BinaryWriter(networkStream);
            }
            catch (Exception ex)
            {
                ClassVar.WriteErrorLog("连接服务器出错:" + Environment.NewLine + "Connect" + ex.ToString());
            }

            //后台心跳消息线程
            Thread threadHeart = new Thread(new ThreadStart(SendHeart));
            threadHeart.IsBackground = true;
            threadHeart.Start();
        }

        // 重连服务器
        /// <summary>
        /// 重连
        /// </summary>
        public void Reconnect()
        {
            try
            {
                if (tcpClient!=null)
                {
                    tcpClient.Close();
                }
                tcpClient = new TcpClient(IP, port);
                //获取网络流
                NetworkStream networkStream = tcpClient.GetStream();
                //将网络流作为二进制读写对象
                br = new BinaryReader(networkStream);
                bw = new BinaryWriter(networkStream);
            }
            catch(Exception ex)
            {
                ClassVar.WriteErrorLog("重连服务器出错:" + Environment.NewLine + "Reconnect" + ex.ToString());
            }
        }

        // 给服务器的心跳,10秒一次
        /// <summary>
        /// 心跳,10秒一次
        /// </summary>
        private void SendHeart()
        {
            while (true)
            {
                Thread.Sleep(10000);
                SendMsg("0000");
            }
        }

        // 发送消息到服务器的方法,带发送长度
        /// <summary>
        /// 发送消息到服务器的方法,带发送长度
        /// </summary>
        /// <param name="msg">消息内容</param>
        public void SendMsg(string msgs)
        {
            try
            {
                //消息中前两个字节表示发送的消息长度
                byte[] msg = Encoding.UTF8.GetBytes(msgs);
                int length = msg.Length;
                short lengthall = (short)(length + 2);
                byte[] lengthByte = System.BitConverter.GetBytes(lengthall);
                byte[] all = lengthByte.Concat(msg).ToArray();
                //然后将字节数组写入网络流
                if (bw != null && tcpClient.Connected==true)
                {
                        bw.Write(all);
                        bw.Flush();
                        if (msgs == "0000")//心跳写单独的文件
                        {
                            ClassVar.WriteLogCommonXT(Environment.NewLine + "成功给系统发送数据:" + msgs);
                        }
                        else
                        {
                            ClassVar.WriteLogCommon(Environment.NewLine + "成功给系统发送数据:" + msgs);
                        }
                }
                else
                {
                    this.Reconnect();
                }
            }
            catch (Exception ex)
            {
                ClassVar.WriteErrorLog("发送消息到服务器出错:" + Environment.NewLine + "SendMsg" + ex.ToString());
            }
        }

        // 发送消息到服务器的方法,老方法,不带长度
        /// <summary>
        /// 发送消息到服务器的方法,老方法,不带长度
        /// </summary>
        /// <param name="msg">消息内容</param>
        public void SendOldMsg(string msg)
        {
                byte[] sendMsg = Encoding.UTF8.GetBytes(msg);
                //然后将字节数组写入网络流
                bw.Write(sendMsg);
                bw.Flush();
        }

        // 将无符号32位整数转换为长度为2的字节数组,大端对齐
        /// <summary>
        /// 将无符号32位整数转换为长度为2的字节数组,大端对齐
        /// </summary>
        /// <param name="value">无符号32位整数</param>
        /// <returns>长度为2的字节数组</returns>
        public byte[] ToBytesArray(int value)
        {
            byte[] buffer = new byte[2];
            for (int i = 1; i >= 0; i--)
            {
                buffer[i] = (byte)(0x000000ff & value);
                value = value >> 8;
            }
            byte temp = buffer[0];
            buffer[0] = buffer[1];
            buffer[1] = temp;
            return buffer;
        }
    }

界面调用方法

 /// <summary>
        /// 本地客户端对象
        /// </summary>
        Client client;
        /// <summary>
        /// 第三方服务器IP地址
        /// </summary>
        string _ServerIP;
        /// <summary>
        /// 第三方服务器端口
        /// </summary>
        int _ServerPort;
        /// <summary>
        /// 第三方系统服务器给本机发送的心跳计时锁对象
        /// </summary>
        public object objTimeSpan = new object();
        /// <summary>
        /// 第三方系统服务器给本机发送的心跳计时
        /// </summary>
        public int timeSpan = 0;
        /// <summary>
        /// 第三方系统服务器发送过来的消息队列锁对象
        /// </summary>
        public object lockQue = new object();
        /// <summary>
        /// 第三方系统服务器发送过来的消息队列
        /// </summary>
        public Queue<string> queueXml = new Queue<string>();

        // 初始化数据
        /// <summary>
        /// 初始化数据
        /// </summary>
        private void Ini()
        {
            //获取本机IPv4地址
            string localIPAddr = GetLocalIP();
            client = new Client(_ServerIP, _ServerPort);
            //连接第三方系统服务器,只用于发送消息用,发送心跳线程
            client.Connect();
            //与第三方系统服务器重连判断线程
            Thread threadChenck = new Thread(new ThreadStart(CheckHeart));
            threadChenck.IsBackground = true;
            threadChenck.Start();
            //启动监听服务器,用于接收发送发送的消息
            TcpListen _TcpListen = new TcpListen(localIPAddr, 11118);
            Thread threadRead = new Thread(ReadQueThread);
            threadRead.IsBackground = true;
            threadRead.Start();
        }

        // 获取本机IPv4地址
        /// <summary>
        /// 获取本机IPv4地址
        /// </summary>
        /// <returns></returns>
        public static string GetLocalIP()
        {
            try
            {
                string HostName = Dns.GetHostName(); //得到主机名
                IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
                for (int i = 0; i < IpEntry.AddressList.Length; i++)
                {
                    //从IP地址列表中筛选出IPv4类型的IP地址
                    //AddressFamily.InterNetwork表示此IP为IPv4,
                    //AddressFamily.InterNetworkV6表示此地址为IPv6类型
                    if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
                    {
                        return IpEntry.AddressList[i].ToString();
                    }
                }
                return "127.0.0.1";
            }
            catch (Exception ex)
            {
                return "127.0.0.1";
            }
        }

        // 与第三方系统重连判断
        /// <summary>
        /// 与第三方系统重连判断
        /// </summary>
        private void CheckHeart()
        {
            while (true)
            {
                Thread.Sleep(3000);
                lock (objTimeSpan)
                {
                    timeSpan = timeSpan + 2;
                }
                if (timeSpan >= maxTime)
                {
                    client.Reconnect();
                    timeSpan = 0;
                }
            }
        }

        //读取第三方系统消息队列,处理后发送到协同
        /// <summary>
        /// 读取第三方系统消息队列,处理后发送到协同
        /// </summary>
        private void ReadQueThread()
        {
            while (true)
            {
                try
                {
                    if (queueXml.Count > 0)
                    {
                        lock (lockQue)
                        {
                            string xml = queueXml.Dequeue();
                            //本地处理
                            FToLocal(xml);
                        }
                    }
                }
                catch (Exception ex)
                {
                    ClassVar.WriteErrorLog("方法ReadQueThread出错,详细信息:" + ex.ToString());
                }
                Thread.Sleep(5);
            }
        } 
时间: 2024-10-12 17:41:00

C#与其他系统通信接口总结的相关文章

货拉拉app开发

做个类似货拉拉APP软件需要多少钱呢?不同的app有不同的功能,所以在了解报价,先来看看物流app开发类似货拉拉APP解决方案.[相关更详细可@廖经理 137*5182*7717] 1.单据录入:随时随地录入物流单据,便于工作人员操作; 2.货物查询:扫一扫即可查询货物处理情况,方便客户操作; 3.价格查询:输入始发地.目的地,选择线路,价格一目了然; 4.门店查询:实时查询离自己最近的店面.车辆,对客户和车主都方便; 5.单据管理系统:按天.按周.按月统计订单数量; 6.数据挖掘:统计和分析物

2012高校GIS论坛

江苏省会议中心 南京·钟山宾馆(2012年4月21-22日) 以"突破与提升"为主题的"2012高校GIS论坛"将于4月在南京举行,由南京大学和工程中心共同承办.高校GIS论坛每两年举办一次,已在北京九华山庄成功举办三届,现已发展成为国内高校GIS教育界最有权威,最具影响力的高端论坛. 赛迪网直播小组正在现场进行图文.微博直播——2012高校GIS论坛! 主持人:尊敬的李院长.曹省长.陈校长,“突破与提升2012高校GIS论坛”现在开幕!首先请允许我介绍出席今天开幕

Linux基础命令及系统设定查看

命令提示符:prompt 每个用户都有其默认shell的设定 查看当前shell的种类-->~]# echo $SHELL [[email protected] ~]# root:当前登录用户的用户名 localhost:当前主机非完整格式的hostname,完整格式为Fully Qualified Domain Name(FQDN) ~:当前用户所在的目录-->非完整格式路径,路径的基名 #:管理员命令提示符 $:普通用户命令提示符 实时管理操作:su,sudo ssh协议:secure s

智能家居系统-框架设计

3.1 控制系统整体设计 智能家居远程控制系统的目标是实现家庭环境下的家用电器的集中网络化控制,并且具有环境参数监测功能,将原来由各自遥控器控制的电器集中到远程网络.服务器.web等终端上进行控制,或者由近端的手机.平板电脑等通过家庭局域网进行控制.总体的说,实现了在任何有网络的地方,就能随心所欲的控制家庭中电器设备的目标. 图3-1  智能家居控制系统技术框图 系统的技术实现如图3-1所示,系统以ARM CORTEX-M3为控制核心,通过GPRS.WIFI.nRF.ZigBee实现对外连接,完

Linux系统基础特性

一.Linux操作系统说明 1.主流的Linux发行版 Linux发行版有数百种之多,常见的版本有以下几种: 1)RedHat:中国和美洲流行 Redhat 9.0个人版2003年停止更新àFedora Core:6个月更新一次 RedHat Enterprise Linux: RHEL --->社区版CentOS: Community ENTerprise OS 2)Slackware 版本 SuSE(商业.开源两种)--->欧洲流行 SLES:SuSE的商业版 OpenSuSE :SuSE

PHP 开发 APP 接口总结 - XML 方式封装通信接口

1.PHP 生成 XML 数据 ① 拼接字符串 ② 使用系统类(DomDocument,XMLWriter,SimpleXML) 例1 使用 PHP 系统类中的 DomDocument 类: <?php $dom = new DomDocument('1.0','utf-8'); $element = $dom->createElement('test','This is a root element'); $dom->appendChild($element); echo $dom-&

Tomcat详解及SNS系统的部署实现

前言:Tomcat是基于java研发的一个web容器,即web服务器,下面我们先简单介绍下Java 一 .Java 1.Java简介 Java是由Sun Micorsystems公司于1995年5月推出的Java面向对象程序设计语言(简称Java语言)和Java平台的总称.用Java实现的HotJava浏览器使得Java被广泛应用起来. 2.Java特点 Java语言是面向对象的语言,以数据为中心来组织程序的,包括数据+方法,方法存放于类中 自身具有API(应用程序编程接口)与ABI(应用程序二

智能园区报修系统——易修 需求说明书 软件概要设计 详细设计说明书

  智能园区报修系统  ——易修                                                                                      队长:马腾俊075                                                                                                       队员:隋锦涛072.于俊杰070.杜世伟071            

ASP.NET MVC4 打造一套UI与后台并重-通用权限系统快速开发框架+精美UI界面 秒杀EasyUi、Ext

一.前言 从进行到软件开发这个行业现在已经有几年了,在整理出这个套开发框架之前自己做了不少重复造轮子的事.每次有新的项目总是要耗费不少时间在UI.权限和系统通用模块上面,自己累得要死,老板还骂没效率.为了能提高开发效率,同时也多拿拿奖金.多存点私房钱,我就着手做了一套以权限管理为主的快速开发框架.不求功能在所有项目中都得到使用,至少要大大提高开发效率. 二.需求分析    根据<那些年我们一起做过的项目>中各类客户对权限模块和通用模块以及UI的要求,我明确了这个系统中要实现的东西. 1.组织机