通用工业视觉软件设计之通讯模块之TcpServer服务端

通用工业视觉软件设计之通讯模块之TcpServer服务端

一 开启服务

   /// <summary>
   /// 开启服务
   /// </summary>
   public bool Start()
   {
       try
       {
           if (!this.IsStartListening)
           {
               // 创建服务套接字实例
               this.ServerSocket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
               // 绑定IP和端口
               this.ServerSocket.Bind(new IPEndPoint(IPAddress.Parse(this.ServerIp), this.ServerPort));
               // 监听
               this.ServerSocket.Listen(10000);
               // 开始监听
               this.IsStartListening = true;
               // 发送信息(调用委托变量,传递参数)
               this.OnTcpServerStateInfoEnterHead(string.Format("服务端Ip:{0},端口:{1}已启动监听", this.ServerIp, this.ServerPort), SocketState.StartListening);
               // 新建服务线程
               this.StartSockst = new Thread(new ThreadStart(this.StartSocketListening));
               // 开启线程
               this.StartSockst.Start();
               return true;
           }
           else
           {
               return true;
           }
       }
       catch (SocketException ex)
       {
           Log.Error(ex.Message);
           this.OnTcpServerErrorMsgEnterHead(ex.Message);
           return false;
       }
   }

二 开始监听

ThreadPool.QueueUserWorkItem(new WaitCallback(this.ClientSocketCallBack), socket);
异步线程启动客户端回调函数,同时传参socket(服务端)

 /// <summary>
 /// 开始监听
 /// </summary>
 public void StartSocketListening()
 {
     try
     {

         while (this.IsStartListening)
         {
             System.Net.Sockets.Socket socket = this.ServerSocket.Accept();
             try
             {
                 Thread.Sleep(10);
                 this.ClientSocketList.Add(socket);
                 string text = ((IPEndPoint)socket.RemoteEndPoint).Address.ToString();
                 string text2 = ((IPEndPoint)socket.RemoteEndPoint).Port.ToString();
                 this.OnTcpServerStateInfoEnterHead(string.Concat(new string[]
                 {
                     "<",
                     text,
                     ":",
                     text2,
                     ">---上线"
                 }), SocketState.ClientOnline);
                 this.OnTcpServerOnlineClientEnterHead(socket);
                 this.OnTcpServerReturnClientCountEnterHead(this.ClientSocketList.Count);
                 ThreadPool.QueueUserWorkItem(new WaitCallback(this.ClientSocketCallBack), socket);
                 Log.Info($"{text} 客户端已经连接");
             }
             catch (Exception)
             {
                 socket.Shutdown(SocketShutdown.Both);
                 this.OnTcpServerOfflineClientEnterHead(socket);
                 this.ClientSocketList.Remove(socket);
             }
         }
     }
     catch (Exception ex)
     {
         this.OnTcpServerErrorMsgEnterHead(ex.Message);
     }
 }

三 辅助函数

  /// <summary>
  /// 客户端数据接收 自动剔除僵尸客户端
  /// </summary>
  /// <param name="obj"></param>
  public void ClientSocketCallBack(object obj)
  {
      System.Net.Sockets.Socket socket = (System.Net.Sockets.Socket)obj;
      while (this.IsStartListening)
      {
          Thread.Sleep(10);
          byte[] array = new byte[1024];
          try
          {
              int num = socket.Receive(array);
              if (num > 0)
              {
                  byte[] array2 = new byte[num];
                  Array.Copy(array, 0, array2, 0, num);
                  this.OnTcpServerReceviceByte(socket, array2);
              }
              else if (num == 0)
              {
                  SocketExitMethod(socket);

                  break;
              }
          }
          catch (Exception ex)
          {
              string ip = ((IPEndPoint)socket.RemoteEndPoint).Address.ToString();
              string port = ((IPEndPoint)socket.RemoteEndPoint).Port.ToString();
              Log.Error($" {ip}:{port} 异常信息为:{ex.Message}");
              SocketExitMethod(socket);
              break;
          }
      }
  }

  /// <summary>
  /// 客户端退出
  /// </summary>
  /// <param name="socket"></param>
  private void SocketExitMethod(System.Net.Sockets.Socket socket)
  {
      this.ClientSocketList.Remove(socket);
      string text = ((IPEndPoint)socket.RemoteEndPoint).Address.ToString();
      string text2 = ((IPEndPoint)socket.RemoteEndPoint).Port.ToString();
      this.OnTcpServerStateInfoEnterHead(string.Concat(new string[]
      {
                      "<",
                      text,
                      ":",
                      text2,
                      ">---下线"
      }), SocketState.ClientOnOff);
      this.OnTcpServerOfflineClientEnterHead(socket);
      this.OnTcpServerReturnClientCountEnterHead(this.ClientSocketList.Count);
      Log.Warn($"{text} 客户端已断开连接");
      try
      {
          socket.Shutdown(SocketShutdown.Both);
      }
      catch
      {
      }
  }
  /// <summary>
  /// 接受数据
  /// </summary>
  /// <param name="temp"></param>
  /// <param name="dataBytes"></param>
  protected virtual void OnTcpServerReceviceByte(System.Net.Sockets.Socket temp, byte[] dataBytes)
  {
      if (this._ReceviceByteEventHandler != null)
      {
          this._ReceviceByteEventHandler(temp, dataBytes);
      }
  }
  /// <summary>
  /// 离线客户端
  /// </summary>
  /// <param name="temp"></param>
  protected virtual void OnTcpServerOfflineClientEnterHead(System.Net.Sockets.Socket temp)
  {
      if (this._AddClientEventHandler2 != null)
      {
          this._AddClientEventHandler2(temp);
      }
  }
  /// <summary>
  /// 状态信息
  /// </summary>
  /// <param name="msg"></param>
  /// <param name="state"></param>
  protected virtual void OnTcpServerStateInfoEnterHead(string msg, SocketState state)
  {
      if (this._StateInfoEventHandler != null)
      {
          this._StateInfoEventHandler(msg, state);
      }
  }

  /// <summary>
  /// 在线客户端
  /// </summary>
  /// <param name="temp"></param>
  protected virtual void OnTcpServerOnlineClientEnterHead(System.Net.Sockets.Socket temp)
  {
      if (this._AddClientEventHandler1 != null)
      {
          this._AddClientEventHandler1(temp);
      }
  }

  /// <summary>
  /// 客户端数量
  /// </summary>
  /// <param name="count"></param>
  protected virtual void OnTcpServerReturnClientCountEnterHead(int count)
  {
      if (this._ReturnClientCountEventHandler != null)
      {
          this._ReturnClientCountEventHandler(count);
      }
  }

  /// <summary>
  /// 错误信息
  /// </summary>
  /// <param name="msg"></param>
  protected virtual void OnTcpServerErrorMsgEnterHead(string msg)
  {
      if (this._ErrorMsgEventHandler != null)
      {
          this._ErrorMsgEventHandler(msg);
      }
  }

四 发送数据

 /// <summary>
 /// 发送数据
 /// </summary>
 /// <param name="ip">IP地址</param>
 /// <param name="port">端口号</param>
 /// <param name="strData">发送字符串</param>
 public void SendData(string ip, int port, string strData, bool isSendByHex)
 {
     System.Net.Sockets.Socket socket = this.ResoultSocket(ip, port);
     try
     {
         if (socket != null)
         {
             byte[] bytes;
             if (isSendByHex == true)
             {
                 bytes = HexTool.HexToByte(HexTool.StrToHexStr(strData));
             }
             else
             {
                 bytes = Encoding.Default.GetBytes(strData);
             }

             List<System.Net.Sockets.Socket> temp = new List<System.Net.Sockets.Socket>();
             temp.Add(socket);
             System.Net.Sockets.Socket.Select(null, temp, null, 1000);
             foreach (System.Net.Sockets.Socket tempSocket in temp)
             {
                 tempSocket.Send(bytes);
             }
         }
     }
     catch (SocketException ex)
     {
         if (socket != null)
         {
             socket.Shutdown(SocketShutdown.Both);
         }
         this.OnTcpServerErrorMsgEnterHead(ex.Message);
     }
 }

返回对应客户端

        /// <summary>
        /// 返回对应客户端
        /// </summary>
        /// <param name="ip">IP地址</param>
        /// <param name="port">端口号</param>
        /// <returns></returns>
        public System.Net.Sockets.Socket ResoultSocket(string ip, int port)
        {
            System.Net.Sockets.Socket result = null;
            try
            {
                // 从客户端队列中获取对应客户端
                foreach (System.Net.Sockets.Socket socket in this.ClientSocketList)
                {
                    if (((IPEndPoint)socket.RemoteEndPoint).Address.ToString().Equals(ip) && port == ((IPEndPoint)socket.RemoteEndPoint).Port)
                    {
                        result = socket;
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                this.OnTcpServerErrorMsgEnterHead(ex.Message);
            }
            return result;
        }



16进制工具助手-HexTool

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ModuleLog;

namespace ModuleCommunication
{
    /// <summary>
    /// 十六进制和string转换
    /// </summary>
    public class HexTool
    {

        #region HexToByte

        public static byte[] HexToByte(string msg)
        {
            //remove any spaces from the string
            msg = msg.Replace(" ", "");
            //create a byte array the length of the
            //divided by 2 (Hex is 2 characters in length)
            byte[] comBuffer = new byte[msg.Length / 2];
            //loop through the length of the provided string
            for (int i = 0; i < msg.Length; i += 2)
                //convert each set of 2 characters to a byte
                //and add to the array
                comBuffer[i / 2] = (byte)Convert.ToByte(msg.Substring(i, 2), 16);
            //return the array
            return comBuffer;
        }

        #endregion

        #region 返回处理后的十六进制字符串

        /// <summary>
        /// 返回处理后的十六进制字符串
        /// </summary>
        /// <param name="mStr"></param>
        /// <returns></returns>
        public static string StrToHexStr(string mStr)
        {
            string str = BitConverter.ToString(
            ASCIIEncoding.Default.GetBytes(mStr)).Replace("-", " ");

            return str;
        }

        #endregion

        #region 返回十六进制代表的字符串

        /// <summary>
        /// 返回十六进制代表的字符串
        /// </summary>
        /// <param name="mHex"></param>
        /// <returns></returns>
        public static string HexStrToStr(string mHex)
        {
            try
            {
                mHex = mHex.Replace(" ", "");
                if (mHex.Length <= 0) return "";
                byte[] vBytes = new byte[mHex.Length / 2];
                for (int i = 0; i < mHex.Length; i += 2)
                    if (!byte.TryParse(mHex.Substring(i, 2), NumberStyles.HexNumber, null, out vBytes[i / 2]))
                        vBytes[i / 2] = 0;
                return ASCIIEncoding.Default.GetString(vBytes);
            }
            catch (Exception)
            {
                Log.Error("无法将十六进制的[{mHex}]转换为string");
                return "";
            }

        }

        #endregion

        #region 字节转十六进制

        public static string ByteToHex(byte[] comByte)
        {
            //create a new StringBuilder object
            StringBuilder builder = new StringBuilder(comByte.Length * 3);
            //loop through each byte in the array
            foreach (byte data in comByte)
                //convert the byte to a string and add to the stringbuilder
                builder.Append(Convert.ToString(data, 16).PadLeft(2, '0').PadRight(3, ' '));
            //return the converted value
            return builder.ToString().ToUpper();
        }

        #endregion

    }
}


五 停止服务

      /// <summary>
      /// 停止服务
      /// </summary>
      public void Stop()
      {
          try
          {
              this.IsStartListening = false;
              if (this.StartSockst != null)
              {
                  this.StartSockst.Interrupt();
                  this.StartSockst.Abort();
              }
              if (this.ServerSocket != null)
              {
                  this.ServerSocket.Close();
              }
              this.OnTcpServerStateInfoEnterHead(string.Format("服务端Ip:{0},端口:{1}已停止监听", this.ServerIp, this.ServerPort), SocketState.StopListening);
              for (int i = 0; i < this.ClientSocketList.Count; i++)
              {
                  this.OnTcpServerOfflineClientEnterHead(this.ClientSocketList[i]);
                  this.ClientSocketList[i].Shutdown(SocketShutdown.Both);
              }
              // GC.Collect();
          }
          catch (SocketException)
          {
          }
      }

六 接收原始Byte数组数据事件

   /// <summary>
   /// 接收原始Byte数组数据事件(线程安全的事件订阅/取消订阅机制)
   /// </summary>
   public event JGTcpServer.ReceviceByteEventHandler OnReceviceByte
   {
       add
       {
           // 1. 获取当前存储的事件处理器委托字段的引用
           JGTcpServer.ReceviceByteEventHandler receviceByteEventHandler = this._ReceviceByteEventHandler;
           JGTcpServer.ReceviceByteEventHandler temp;
           do
           {            
               // 2. 保存当前值到临时变量
               temp = receviceByteEventHandler;
               // 3. 将新的事件处理器(value)与当前处理器组合
               JGTcpServer.ReceviceByteEventHandler value2 = (JGTcpServer.ReceviceByteEventHandler)Delegate.Combine(temp, value);
               // 4. 原子性地尝试更新字段:
               //    - 如果字段仍然是temp值,则替换为value2
               //    - 返回交换前的实际值
               receviceByteEventHandler = Interlocked.CompareExchange<JGTcpServer.ReceviceByteEventHandler>(ref this._ReceviceByteEventHandler, value2, temp);
           }
           // 多线程并发修改 检查 当前实际值 和 本次操作开始时的原始值 是否 仍然相同。
           //如果不同,说明 其他线程已经修改了事件处理器,本次修改可能基于过期数据,需要 重新读取最新值并重试。
           //如果相同,说明 没有其他线程干扰,本次修改成功,可以退出循环。
           while (receviceByteEventHandler != temp);
       }
       //移除事件
       remove
       {
           JGTcpServer.ReceviceByteEventHandler receviceByteEventHandler = this._ReceviceByteEventHandler;
           JGTcpServer.ReceviceByteEventHandler temp;
           do
           {
               temp = receviceByteEventHandler;
               JGTcpServer.ReceviceByteEventHandler value2 = (JGTcpServer.ReceviceByteEventHandler)Delegate.Remove(temp, value);
               receviceByteEventHandler = Interlocked.CompareExchange<JGTcpServer.ReceviceByteEventHandler>(ref this._ReceviceByteEventHandler, value2, temp);
           }
           while (receviceByteEventHandler != temp);
       }
   }

七 新客户端上线时返回客户端事件

 /// <summary>
 /// 新客户端上线时返回客户端事件
 /// </summary>
 public event JGTcpServer.AddClientEventHandler OnOnlineClient
 {
     add
     {
         JGTcpServer.AddClientEventHandler addClientEventHandler = this._AddClientEventHandler1;
         JGTcpServer.AddClientEventHandler temp;
         do
         {
             temp = addClientEventHandler;
             JGTcpServer.AddClientEventHandler value2 = (JGTcpServer.AddClientEventHandler)Delegate.Combine(temp, value);
             addClientEventHandler = Interlocked.CompareExchange<JGTcpServer.AddClientEventHandler>(ref this._AddClientEventHandler1, value2, temp);
         }
         while (addClientEventHandler != temp);
     }
     remove
     {
         JGTcpServer.AddClientEventHandler addClientEventHandler = this._AddClientEventHandler1;
         JGTcpServer.AddClientEventHandler temp;
         do
         {
             temp = addClientEventHandler;
             JGTcpServer.AddClientEventHandler value2 = (JGTcpServer.AddClientEventHandler)Delegate.Remove(temp, value);
             addClientEventHandler = Interlocked.CompareExchange<JGTcpServer.AddClientEventHandler>(ref this._AddClientEventHandler1, value2, temp);
         }
         while (addClientEventHandler != temp);
     }
 }

八 客户端下线时返回客户端事件

    /// <summary>
    /// 客户端下线时返回客户端事件
    /// </summary>
    public event JGTcpServer.AddClientEventHandler OnOfflineClient
    {
        add
        {
            JGTcpServer.AddClientEventHandler addClientEventHandler = this._AddClientEventHandler2;
            JGTcpServer.AddClientEventHandler temp;
            do
            {
                temp = addClientEventHandler;
                JGTcpServer.AddClientEventHandler value2 = (JGTcpServer.AddClientEventHandler)Delegate.Combine(temp, value);
                addClientEventHandler = Interlocked.CompareExchange<JGTcpServer.AddClientEventHandler>(ref this._AddClientEventHandler2, value2, temp);
            }
            while (addClientEventHandler != temp);
        }
        remove
        {
            JGTcpServer.AddClientEventHandler addClientEventHandler = this._AddClientEventHandler2;
            JGTcpServer.AddClientEventHandler temp;
            do
            {
                temp = addClientEventHandler;
                JGTcpServer.AddClientEventHandler value2 = (JGTcpServer.AddClientEventHandler)Delegate.Remove(temp, value);
                addClientEventHandler = Interlocked.CompareExchange<JGTcpServer.AddClientEventHandler>(ref this._AddClientEventHandler2, value2, temp);
            }
            while (addClientEventHandler != temp);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值