zoukankan      html  css  js  c++  java
  • C# WPF上位机实现和下位机TCP通讯

    下位机使用北京大华程控电源DH1766-1,上位机使用WPF。实现了电压电流实时采集,曲线显示。上午在公司调试成功,手头没有程控电源,使用TCP服务端模拟。昨天写的TCP服务端正好排上用场。

    界面如下:

    服务端

    服务端实在上篇基础上实现的。需要做如下更改:

    while (true)
                              {
                                  try
                                  {
                                      byte[] bufferDate = new byte[1024];
                                      int realLen = pSocket.Receive(bufferDate);
                                      if (realLen <= 0)
                                      {
                                          this.Invoke(addTextDelegate, pSocket.RemoteEndPoint.ToString() + "退出 ");
                                          socketList.Remove(pSocket);
                                          //客户端退出的时候会发送一个空字节
                                          pSocket.Shutdown(SocketShutdown.Both);
                                          pSocket.Close();
                                          return;
                                      }
                                      string receiveStr = Encoding.Default.GetString(bufferDate, 0, realLen);
                                      switch (receiveStr)
                                      {
                                          case "MEAS:VOLTage:ALL? ":
                                              proxSocket.Send(Encoding.Default.GetBytes(r.Next(16,25).ToString()+ ","+r.Next(16, 25).ToString()+","+ r.Next(16, 25).ToString()));
                                              break;
                                          case "MEAS:CURR:ALL? ":
                                              proxSocket.Send(Encoding.Default.GetBytes(r.Next(2, 5).ToString() + "," + r.Next(2, 5).ToString() + "," + r.Next(2, 5).ToString()));
                                              break;
                                          default:
                                              break;
                                      }
                                      this.Invoke(addTextDelegate, receiveStr + "from" + pSocket.RemoteEndPoint.ToString() + " ");
                                  }
                                  catch (Exception ex)
                                  {
                                      this.Invoke(addTextDelegate, pSocket.RemoteEndPoint.ToString() + "异常退出 ");
                                      socketList.Remove(pSocket);
                                      pSocket.Shutdown(SocketShutdown.Both);
                                      pSocket.Close();
                                      return;
                                  }
                              }

    在While循环中加入:

     switch (receiveStr)
    {
      case "MEAS:VOLTage:ALL? ":
      proxSocket.Send(Encoding.Default.GetBytes(r.Next(16,25).ToString()+ ","+r.Next(16, 25).ToString()+","+ r.Next(16, 25).ToString()));
      break;
      case "MEAS:CURR:ALL? ":
      proxSocket.Send(Encoding.Default.GetBytes(r.Next(2, 5).ToString() + "," + r.Next(2, 5).ToString() + "," + r.Next(2, 5).ToString()));
      break;
      default:
      break;

    }

    模拟电源,当收到电压查询时,发送16~25中随机数,由于电源是三个通道的,因此发送三个随机数,用逗号隔开。同样收到电流查询,发送2~5之间的随机数。

    完整的客户端源码:

    public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                addTextDelegate = new AddTextDelegate(AddText);
            }
            private AddTextDelegate addTextDelegate;
            private List<Socket> socketList = new List<Socket>();
    
            public delegate void AddTextDelegate(string text);
            private void AddText(string text)
            {
                txtLog.Text += text;
            }
    
            Random r = new Random();
    
            private void btnStart_Click(object sender, EventArgs e)
            {
                //参数:寻址方式    传输数据方式  通信协议
                Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
    
                IPAddress iPAddress = IPAddress.Parse(txtIP.Text);
    
                //创建EndPoint
                IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, int.Parse(txtPort.Text));
    
                //绑定端口
                socket.Bind(iPEndPoint);
    
                //开启侦听
                socket.Listen(10);
    
                txtLog.Text += "服务启动开启侦听……
    ";
    
                Thread thread = new Thread((s) =>
                  {
                      Socket serSocket = (Socket)s;
                      while (true)//不断接收客户端连接
                      {
                          this.Invoke(addTextDelegate, "服务正在等待客户端连接……
    ");
    
                          //开始接收客户端的连接
                          //阻塞当前线程,等待客户端连接
                          //客户端连接上之后,服务端自动生成一个socket和连接的客端通信
                          Socket proxSocket = serSocket.Accept();
    
                          this.Invoke(addTextDelegate, "客户端连接成功!
    " + proxSocket.RemoteEndPoint.ToString());
    
                          //proxSocket.Send(Encoding.Default.GetBytes("连接成功!"));
    
                          socketList.Add(proxSocket);//当前通信的socket放到集合中
    
                          new Thread(p =>
                          {
                              Socket pSocket = (Socket)p;
                              while (true)
                              {
                                  try
                                  {
                                      byte[] bufferDate = new byte[1024];
                                      int realLen = pSocket.Receive(bufferDate);
    
                                      if (realLen <= 0)
                                      {
                                          this.Invoke(addTextDelegate, pSocket.RemoteEndPoint.ToString() + "退出
    ");
    
                                          socketList.Remove(pSocket);
                                          //客户端退出的时候会发送一个空字节
                                          pSocket.Shutdown(SocketShutdown.Both);
                                          pSocket.Close();
    
                                          return;
                                      }
                                      string receiveStr = Encoding.Default.GetString(bufferDate, 0, realLen);
                                      switch (receiveStr)
                                      {
                                          case "MEAS:VOLTage:ALL?
    ":
                                              proxSocket.Send(Encoding.Default.GetBytes(r.Next(16,25).ToString()+ ","+r.Next(16, 25).ToString()+","+ r.Next(16, 25).ToString()));
                                              break;
                                          case "MEAS:CURR:ALL?
    ":
                                              proxSocket.Send(Encoding.Default.GetBytes(r.Next(2, 5).ToString() + "," + r.Next(2, 5).ToString() + "," + r.Next(2, 5).ToString()));
                                              break;
                                          default:
                                              break;
                                      }
                                      this.Invoke(addTextDelegate, receiveStr + "from" + pSocket.RemoteEndPoint.ToString() + "
    ");
                                  }
                                  catch (Exception ex)
                                  {
                                      this.Invoke(addTextDelegate, pSocket.RemoteEndPoint.ToString() + "异常退出
    ");
    
                                      socketList.Remove(pSocket);
                                      pSocket.Shutdown(SocketShutdown.Both);
                                      pSocket.Close();
                                      return;
                                  }
                              }
                          })
                          { IsBackground = true }.Start(proxSocket);
                      }
                  });
                thread.IsBackground = true;
                thread.Start(socket);
               
            }
    
            private void btnSend_Click(object sender, EventArgs e)
            {
                string str = txtSend.Text;
                byte[] data = Encoding.Default.GetBytes(str);
                foreach (var socket in socketList)
                {
                    if (socket != null && socket.Connected)
                    {
                        socket.Send(data);
                    }
                }
            }
        }

    上位机实现客户端功能。具体如下:

    1、字段和属性

    public readonly IPEndPoint TagetIPEP;
    public bool IsConnected { get; set; } = false;
    private Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { /*ReceiveTimeout=1000,SendTimeout=1000*/};
    private Thread recListenThread;
    public string ReceiveStr { get; set; }
    public byte[] ReceiveByte { get; set; }
    TagetIPEP是服务器地址和端口。
    IsConnected是连接的状态,这个比较重要,在发送和接收时,都要更加IsConnected进行,并更新IsConnected。
    Socket用于和客户端通讯。
    recListenThread是监听客户端消息的线程。
    ReceiveStr和ReceiveByte用来存储客户端发来的消息。
    2、方法函数
    连接方法:
     public bool Connect()
            {
                try
                {
                    socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
                    {
                        //ReceiveTimeout = 1000,
                        //SendTimeout=1000
                    };
    
                    //IAsyncResult connResult = socket.BeginConnect(TagetIPEP.Address, TagetIPEP.Port, null, null);
                    //connResult.AsyncWaitHandle.WaitOne(5000, true);
                    //if (connResult.IsCompleted)
                    //{
                    socket.Connect(TagetIPEP.Address, TagetIPEP.Port);
                    IsConnected = true;
                        //开启接收监听
    
                        recListenThread = new Thread(() =>
                        {
                            while (true)
                            {
                                try
                                {
                                    ReceiveByte = new byte[1024];
                                    int realLen = socket.Receive(ReceiveByte);
                                    ReceiveStr = Encoding.Default.GetString(ReceiveByte, 0, realLen);
                                    ReceiveEvent();
                                    if (realLen <= 0)
                                    {
                                        if (socket != null && socket.Connected)
                                        {
                                            //服务器退出
                                            IsConnected = false;
                                            Log.WriteLog("服务器退出!");
                                            socket.Shutdown(SocketShutdown.Both);
                                            socket.Close();
                                            MessageBox.Show("连接断开!");
                                        }
                                        return;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    if (socket != null && socket.Connected)
                                    {
                                        IsConnected = false;
                                        Log.WriteLog("服务器异常退出!", ex);
                                        socket.Shutdown(SocketShutdown.Both);
                                        socket.Close();
                                    }
                                    return;
                                }
                            }
                        })
                        { IsBackground = true };
                        recListenThread.Start();
                        return true;
                    //}
    
                }
                catch (Exception ex)
                {
                    Log.WriteLog(TagetIPEP.Address + "连接失败", ex);
                }
                return false;
            }

     连接函数返回值为bool类型,根据返回值判断连接是否成功连接。这里每次连接都实例化了一个socket,因为在执行socket.close()后,重新打开会失败,而断线重连会经常用到,没有找到更好的方法,干脆重新实例化socket。连接成功后,开启监听服务端消息的线程。这里使用了一个ReceiveEvent()事件,在接收到消息时会触发这个事件,刷新UI界面。

    发送方法:

       public bool Send(string msg)
            {
                byte[] sendMsg = Encoding.Default.GetBytes(msg);
                if (sendMsg.Length > 0&&IsConnected)
                {
                    if (socket != null && socket.Connected)
                    {
                        try
                        {
                            socket.Send(sendMsg);
                            return true;
                        }
                        catch (Exception ex)
                        {
                            IsConnected = false;
                            Log.WriteLog("发送数据失败,目标地址" + TagetIPEP.Address, ex);
                        }
                    }
                }
    
                return false;
    
            }

    关闭方法:

        public void Close()
            {
                if (socket != null && socket.Connected)
                {
                    IsConnected = false;
                    recListenThread.Abort();
                    Log.WriteLog("关闭连接!");
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Close();
                }
            }

    在出现异常时调用

    消息接收事件:

     public event Action ReceiveEvent;

    每次接收消息时触发,获取属性ReceiveStr和ReceiveByte的值,刷新UI界面。

    完整代码:

    public class TCPClient
        {
            public TCPClient(/*IPEndPoint localIPEP,*/IPEndPoint targetIPEP)
            {
                //socket.Bind(localIPEP);
                TagetIPEP = targetIPEP;
               
            }
    
            public readonly IPEndPoint TagetIPEP;
    
            public bool IsConnected { get; set; } = false;
    
            private Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { /*ReceiveTimeout=1000,SendTimeout=1000*/};
    
            public bool Connect()
            {
                try
                {
                    socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
                    {
                        //ReceiveTimeout = 1000,
                        //SendTimeout=1000
                    };
    
                    //IAsyncResult connResult = socket.BeginConnect(TagetIPEP.Address, TagetIPEP.Port, null, null);
                    //connResult.AsyncWaitHandle.WaitOne(5000, true);
                    //if (connResult.IsCompleted)
                    //{
                    socket.Connect(TagetIPEP.Address, TagetIPEP.Port);
                    IsConnected = true;
                        //开启接收监听
    
                        recListenThread = new Thread(() =>
                        {
                            while (true)
                            {
                                try
                                {
                                    ReceiveByte = new byte[1024];
                                    int realLen = socket.Receive(ReceiveByte);
                                    ReceiveStr = Encoding.Default.GetString(ReceiveByte, 0, realLen);
                                    ReceiveEvent();
                                    if (realLen <= 0)
                                    {
                                        if (socket != null && socket.Connected)
                                        {
                                            //服务器退出
                                            IsConnected = false;
                                            Log.WriteLog("服务器退出!");
                                            socket.Shutdown(SocketShutdown.Both);
                                            socket.Close();
                                            MessageBox.Show("连接断开!");
                                        }
                                        return;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    if (socket != null && socket.Connected)
                                    {
                                        IsConnected = false;
                                        Log.WriteLog("服务器异常退出!", ex);
                                        socket.Shutdown(SocketShutdown.Both);
                                        socket.Close();
                                    }
                                    return;
                                }
                            }
                        })
                        { IsBackground = true };
                        recListenThread.Start();
                        return true;
                    //}
    
                }
                catch (Exception ex)
                {
                    Log.WriteLog(TagetIPEP.Address + "连接失败", ex);
                }
                return false;
            }
    
            public bool Send(string msg)
            {
                byte[] sendMsg = Encoding.Default.GetBytes(msg);
                if (sendMsg.Length > 0&&IsConnected)
                {
                    if (socket != null && socket.Connected)
                    {
                        try
                        {
                            socket.Send(sendMsg);
                            return true;
                        }
                        catch (Exception ex)
                        {
                            IsConnected = false;
                            Log.WriteLog("发送数据失败,目标地址" + TagetIPEP.Address, ex);
                        }
                    }
                }
    
                return false;
    
            }
    
            public event Action ReceiveEvent;
    
            public string ReceiveStr { get; set; }
    
            public byte[] ReceiveByte { get; set; }
    
            public void Close()
            {
                if (socket != null && socket.Connected)
                {
                    IsConnected = false;
                    recListenThread.Abort();
                    Log.WriteLog("关闭连接!");
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Close();
                }
            }
    
            private Thread recListenThread;
    
        }

    前台调用,声明Timer定时器,每个一秒触发一次。触发事件如下:

            private string flag = "";
            private void QueryTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            {
                Now = DateTime.Now;
    
                if (!tcp.Send("MEAS:VOLTage:ALL?
    "))
                {
                    queryTimer.Enabled = false;
                    StartContent = "开始";
                    ConnContent = "连接";
                    tcp.IsConnected = false;
                    MessageBox.Show("查询失败!");
                    return;
                }
                flag = "V";
                Thread.Sleep(50);
    
                if (!tcp.Send("MEAS:CURR:ALL?
    "))
                {
                    queryTimer.Enabled = false;
                    StartContent = "开始";
                    ConnContent = "连接";
                    tcp.IsConnected = false;
                    MessageBox.Show("查询失败!");
                    return;
                }
                flag = "C";
    
                #region 测试
                //angle += 18;
                //if (angle > 360)
                //{
                //    angle = 18;
                //}
    
                #endregion
    
            }

    刷新UI界面的事件如下:

      private void Tcp_ReceiveEvent()
            {
                Task.Run(() =>
                {
                    Application.Current.Dispatcher.Invoke(() =>
                    {
                        RemoteIP = tcp.TagetIPEP.ToString();
                        switch (flag)
                        {
                            case "V":
                                VoltValue = Math.Round(Convert.ToDouble(tcp.ReceiveStr.Split(',')[0]), 3);
                                break;
                            case "C":
                                CurrentValue = Math.Round(Convert.ToDouble(tcp.ReceiveStr.Split(',')[0]), 3);
                                break;
                            default:
                                break;
                        }
    
                        #region 测试
                        //VoltValue = Math.Round(Math.Sin((angle) * pi / 180) * 16 + 16, 3);
                        //CurrentValue = Math.Round(Math.Sin((angle) * pi / 180) * 2.5 + 2.5, 3);
                        #endregion
    
                        VoltValues.Add(VoltValue);
                        CurrentValues.Add(CurrentValue);
    
                        if (VoltValues.Count > 30)
                        {
                            VoltValues.RemoveAt(0);
                            CurrentValues.RemoveAt(0);
                        }
                    });
                });
            }
  • 相关阅读:
    kafka----简单的脚本命令重点
    kafka简单学习----遇到的问题
    nc简单使用
    kafka-sparkstreaming---学习1
    sparkStream---1
    装系统
    spark入门备忘---1
    linux---学习3
    MySql-5.7.17-20解压缩版安装配置
    springboot动态定时任务
  • 原文地址:https://www.cnblogs.com/Samberger/p/10561243.html
Copyright © 2011-2022 走看看