通用工业视觉软件设计之通讯模块之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);
}
}