20240301_JSEQ_upperpc/JiangsuEarthquakeJM/JiangsuEarthquake/Common/Server.cs

332 lines
11 KiB
C#
Raw Normal View History

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
}
}
}
}