332 lines
11 KiB
C#
332 lines
11 KiB
C#
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
|
||
}
|
||
}
|
||
}
|
||
}
|