20240301_JSEQ_upperpc/JiangsuEarthquakeJM/JiangsuEarthquake/Common/Server.cs
春风过客 d7f51483a7 新增功能:
1 将地震仪数据读取功能单独成一个页面;
2024-05-13 18:51:05 +08:00

332 lines
11 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using static JiangsuEarthquake.Common.Sockets;
namespace JiangsuEarthquake.Common
{
public class Server : SocketObject
{
public PushSockets pushSockets;
bool IsStop = false;
object obj = new object();
/// <summary>
/// 信号量
/// </summary>
private Semaphore semap = new Semaphore(5, 5000);
/// <summary>
/// 客户端队列集合
/// </summary>
public List<Sockets> ClientList = new List<Sockets>();
/// <summary>
/// 服务端
/// </summary>
private TcpListener listener;
/// <summary>
/// 当前IP地址
/// </summary>
private IPAddress Ipaddress;
/// <summary>
/// 校时信息
/// </summary>
public List<byte> TimingList = new List<byte>();
/// <summary>
/// 当前监听端口
/// </summary>
private int Port;
/// <summary>
/// 当前IP,端口对象
/// </summary>
private IPEndPoint ip;
/// <summary>
/// 初始化服务端对象
/// </summary>
/// <param name="ipaddress">IP地址</param>
/// <param name="port">监听端口</param>
public override void InitSocket(IPAddress ipaddress, int port)
{
Ipaddress = ipaddress;
Port = port;
listener = new TcpListener(Ipaddress, Port);
}
/// <summary>
/// 初始化服务端对象
/// </summary>
/// <param name="ipaddress">IP地址</param>
/// <param name="port">监听端口</param>
public override void InitSocket(string ipaddress, int port)
{
Ipaddress = IPAddress.Parse(ipaddress);
Port = port;
ip = new IPEndPoint(Ipaddress, Port);
listener = new TcpListener(Ipaddress, Port);
}
/// <summary>
/// 启动监听,并处理连接
/// </summary>
public override bool Start()
{
try
{
listener.Start();
Thread AccTh = new Thread(new ThreadStart(delegate
{
while (true)
{
if (IsStop != false)
{
break;
}
GetAcceptTcpClient();
Thread.Sleep(1);
}
}));
AccTh.Start();
return true;
}
catch (SocketException skex)
{
Sockets sks = new Sockets();
sks.ex = skex;
if (pushSockets != null)
pushSockets.Invoke(sks);//推送至UI
return false;
}
}
/// <summary>
/// 停止
/// </summary>
public override void Stop()
{
if (listener != null)
{
listener.Stop();
listener = null;
IsStop = true;
pushSockets = null;
}
}
/// <summary>
/// 等待处理新的连接
/// </summary>
private void GetAcceptTcpClient()
{
try
{
if (listener.Pending())
{
semap.WaitOne();
TcpClient tclient = listener.AcceptTcpClient();
//维护客户端队列
Socket socket = tclient.Client;
NetworkStream stream = new NetworkStream(socket, true); //承载这个Socket
Sockets sks = new Sockets(tclient.Client.RemoteEndPoint as IPEndPoint, tclient, stream);
sks.NewClientFlag = true;
//推送新客户端
if (pushSockets != null)
pushSockets.Invoke(sks);
//客户端异步接收
sks.nStream.BeginRead(sks.RecBuffer, 0, sks.RecBuffer.Length, new AsyncCallback(EndReader), sks);
//加入客户端集合.
AddClientList(sks);
//主动向客户端发送校时信息
if (stream.CanWrite)
{
TimingList.Clear();
TimingList.AddRange(new byte[2] { 0xFE, 0xEF }); //帧头H=0xFE 0xEF)
TimingList.AddRange(new byte[2] { 0x00, 0x08 }); //长度L=4+4)(MSH MSL(从地址码到最后)
TimingList.Add(0x00); //地址码(ADDR=00)
TimingList.Add(0x06); //功能码FUNC=06)
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 8, 0, 0, 0);
int totalSeconds = (int)ts.TotalSeconds;
string hexSeconds = totalSeconds.ToString("X2");
byte[] timeByte = Tools.HexStringToByteArray(hexSeconds);
TimingList.AddRange(timeByte); //UTC时间
byte checkSum = Tools.CheckSum(TimingList.ToArray());
TimingList.Add(checkSum); //校验(CS = 帧头 ...+... 传感器数据)
TimingList.Add(0x16); //结束符(0x16)
stream.Write(TimingList.ToArray(), 0, TimingList.Count);
}
semap.Release();
}
}
catch
{
return;
}
}
/// <summary>
/// 异步接收发送的信息.
/// </summary>
/// <param name="ir"></param>
private void EndReader(IAsyncResult ir)
{
Sockets sks = ir.AsyncState as Sockets;
if (sks != null && listener != null)
{
try
{
if (sks.NewClientFlag || sks.Offset != 0)
{
sks.NewClientFlag = false;
sks.Offset = sks.nStream.EndRead(ir);
if (pushSockets != null)
pushSockets.Invoke(sks);//推送至UI
sks.nStream.BeginRead(sks.RecBuffer, 0, sks.RecBuffer.Length, new AsyncCallback(EndReader), sks);
}
}
catch (Exception skex)
{
lock (obj)
{
//移除异常类
ClientList.Remove(sks);
Sockets sk = sks;
sk.ClientDispose = true;//客户端退出
sk.ex = skex;
if (pushSockets != null)
pushSockets.Invoke(sks);//推送至UI
}
}
}
}
/// <summary>
/// 加入队列.
/// </summary>
/// <param name="sk"></param>
private void AddClientList(Sockets sk)
{
//虽然有信号量,还是用lock增加系数
lock (obj)
{
Sockets sockets = ClientList.Find(o => { return o.Ip == sk.Ip; });
//如果不存在则添加,否则更新
if (sockets == null)
{
ClientList.Add(sk);
}
else
{
ClientList.Remove(sockets);
ClientList.Add(sk);
}
}
}
/// <summary>
/// 向所有在线的客户端发送信息.
/// </summary>
/// <param name="SendData">发送的byte[]</param>
public void SendToAll(byte[] SendData)
{
try
{
Parallel.ForEach(ClientList, new ParallelOptions() { MaxDegreeOfParallelism = 5 }, item =>
{
if (item != null)
SendToClient(item.Ip, SendData);
});
}
catch (Exception ex)
{
//Console.Write(ex.Message);
}
}
/// <summary>
/// 向某一位客户端发送信息
/// </summary>
/// <param name="ip">客户端IP+端口地址</param>
/// <param name="SendData">发送的数据包</param>
public void SendToClient(IPEndPoint ip, byte[] SendData)
{
try
{
Sockets sks = ClientList.Find(o => { return o.Ip == ip; });
if (sks == null || !sks.Client.Connected || sks.ClientDispose)
{
//没有连接时,标识退出
Sockets ks = new Sockets();
sks.ClientDispose = true;//标识客户端下线
sks.ex = new Exception("客户端无连接");
if (pushSockets != null)
pushSockets.Invoke(sks);//推送至UI
ClientList.Remove(sks);
}
if (sks.Client.Connected)
{
//获取当前流进行写入.
NetworkStream nStream = sks.nStream;
if (nStream.CanWrite)
{
//byte[] buffer = Encoding.UTF8.GetBytes(SendData);
nStream.Write(SendData, 0, SendData.Length);
}
else
{
//避免流被关闭,重新从对象中获取流
nStream = sks.Client.GetStream();
if (nStream.CanWrite)
{
//byte[] buffer = Encoding.UTF8.GetBytes(SendData);
nStream.Write(SendData, 0, SendData.Length);
}
else
{
//如果还是无法写入,那么认为客户端中断连接.
ClientList.Remove(sks);
Sockets ks = new Sockets();
sks.ClientDispose = true;//如果出现异常,标识客户端下线
sks.ex = new Exception("客户端无连接");
if (pushSockets != null)
pushSockets.Invoke(sks);//推送至UI
}
}
}
}
catch (Exception skex)
{
Sockets sks = new Sockets();
sks.ClientDispose = true;//如果出现异常,标识客户端退出
sks.ex = skex;
if (pushSockets != null)
pushSockets.Invoke(sks);//推送至UI
}
}
}
}