3 changed files with 411 additions and 190 deletions
@ -0,0 +1,404 @@ |
|||||
|
using DyeingComputer.UserClass; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Data; |
||||
|
using System.Linq; |
||||
|
using System.Net; |
||||
|
using System.Net.Http; |
||||
|
using System.Net.Sockets; |
||||
|
using System.Reflection.Emit; |
||||
|
using System.Text; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using System.Diagnostics; |
||||
|
|
||||
|
namespace DyeingComputer.UserClass |
||||
|
{/// <summary>
|
||||
|
/// 异步TCP服务器
|
||||
|
/// </summary>
|
||||
|
public class AsyncTcpServer : IDisposable |
||||
|
{ |
||||
|
#region Fields
|
||||
|
|
||||
|
private TcpListener listener; |
||||
|
private List<TcpClientState> clients; |
||||
|
private bool disposed = false; |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region Ctors
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 异步TCP服务器
|
||||
|
/// </summary>
|
||||
|
/// <param name="listenPort">监听的端口</param>
|
||||
|
public AsyncTcpServer(int listenPort) |
||||
|
: this(IPAddress.Any, listenPort) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 异步TCP服务器
|
||||
|
/// </summary>
|
||||
|
/// <param name="localEP">监听的终结点</param>
|
||||
|
public AsyncTcpServer(IPEndPoint localEP) |
||||
|
: this(localEP.Address, localEP.Port) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 异步TCP服务器
|
||||
|
/// </summary>
|
||||
|
/// <param name="localIPAddress">监听的IP地址</param>
|
||||
|
/// <param name="listenPort">监听的端口</param>
|
||||
|
public AsyncTcpServer(IPAddress localIPAddress, int listenPort) |
||||
|
{ |
||||
|
Address = localIPAddress; |
||||
|
Port = listenPort; |
||||
|
this.Encoding = Encoding.Default; |
||||
|
|
||||
|
clients = new List<TcpClientState>(); |
||||
|
|
||||
|
listener = new TcpListener(Address, Port); |
||||
|
listener.AllowNatTraversal(true); |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region Properties
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 服务器是否正在运行
|
||||
|
/// </summary>
|
||||
|
public bool IsRunning { get; private set; } |
||||
|
/// <summary>
|
||||
|
/// 监听的IP地址
|
||||
|
/// </summary>
|
||||
|
public IPAddress Address { get; private set; } |
||||
|
/// <summary>
|
||||
|
/// 监听的端口
|
||||
|
/// </summary>
|
||||
|
public int Port { get; private set; } |
||||
|
/// <summary>
|
||||
|
/// 通信使用的编码
|
||||
|
/// </summary>
|
||||
|
public Encoding Encoding { get; set; } |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region Server
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 启动服务器
|
||||
|
/// </summary>
|
||||
|
/// <returns>异步TCP服务器</returns>
|
||||
|
public AsyncTcpServer Start() |
||||
|
{ |
||||
|
if (!IsRunning) |
||||
|
{ |
||||
|
IsRunning = true; |
||||
|
listener.Start(); |
||||
|
listener.BeginAcceptTcpClient( |
||||
|
new AsyncCallback(HandleTcpClientAccepted), listener); |
||||
|
} |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 启动服务器
|
||||
|
/// </summary>
|
||||
|
/// <param name="backlog">
|
||||
|
/// 服务器所允许的挂起连接序列的最大长度
|
||||
|
/// </param>
|
||||
|
/// <returns>异步TCP服务器</returns>
|
||||
|
public AsyncTcpServer Start(int backlog) |
||||
|
{ |
||||
|
if (!IsRunning) |
||||
|
{ |
||||
|
IsRunning = true; |
||||
|
listener.Start(backlog); |
||||
|
listener.BeginAcceptTcpClient( |
||||
|
new AsyncCallback(HandleTcpClientAccepted), listener); |
||||
|
} |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 停止服务器
|
||||
|
/// </summary>
|
||||
|
/// <returns>异步TCP服务器</returns>
|
||||
|
public AsyncTcpServer Stop() |
||||
|
{ |
||||
|
if (IsRunning) |
||||
|
{ |
||||
|
IsRunning = false; |
||||
|
listener.Stop(); |
||||
|
|
||||
|
lock (this.clients) |
||||
|
{ |
||||
|
for (int i = 0; i < this.clients.Count; i++) |
||||
|
{ |
||||
|
this.clients[i].TcpClient.Client.Disconnect(false); |
||||
|
} |
||||
|
this.clients.Clear(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region Receive
|
||||
|
|
||||
|
private void HandleTcpClientAccepted(IAsyncResult ar) |
||||
|
{ |
||||
|
if (IsRunning) |
||||
|
{ |
||||
|
TcpListener tcpListener = (TcpListener)ar.AsyncState; |
||||
|
|
||||
|
TcpClient tcpClient = tcpListener.EndAcceptTcpClient(ar); |
||||
|
byte[] buffer = new byte[tcpClient.ReceiveBufferSize]; |
||||
|
|
||||
|
TcpClientState internalClient |
||||
|
= new TcpClientState(tcpClient, buffer); |
||||
|
lock (this.clients) |
||||
|
{ |
||||
|
this.clients.Add(internalClient); |
||||
|
RaiseClientConnected(tcpClient); |
||||
|
} |
||||
|
|
||||
|
NetworkStream networkStream = internalClient.NetworkStream; |
||||
|
networkStream.BeginRead( |
||||
|
internalClient.Buffer, |
||||
|
0, |
||||
|
internalClient.Buffer.Length, |
||||
|
HandleDatagramReceived, |
||||
|
internalClient); |
||||
|
|
||||
|
tcpListener.BeginAcceptTcpClient( |
||||
|
new AsyncCallback(HandleTcpClientAccepted), ar.AsyncState); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void HandleDatagramReceived(IAsyncResult ar) |
||||
|
{ |
||||
|
if (IsRunning) |
||||
|
{ |
||||
|
TcpClientState internalClient = (TcpClientState)ar.AsyncState; |
||||
|
NetworkStream networkStream = internalClient.NetworkStream; |
||||
|
|
||||
|
int numberOfReadBytes = 0; |
||||
|
try |
||||
|
{ |
||||
|
numberOfReadBytes = networkStream.EndRead(ar); |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
numberOfReadBytes = 0; |
||||
|
} |
||||
|
|
||||
|
if (numberOfReadBytes == 0) |
||||
|
{ |
||||
|
// connection has been closed
|
||||
|
lock (this.clients) |
||||
|
{ |
||||
|
this.clients.Remove(internalClient); |
||||
|
RaiseClientDisconnected(internalClient.TcpClient); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// received byte and trigger event notification
|
||||
|
byte[] receivedBytes = new byte[numberOfReadBytes]; |
||||
|
Buffer.BlockCopy( |
||||
|
internalClient.Buffer, 0, |
||||
|
receivedBytes, 0, numberOfReadBytes); |
||||
|
RaiseDatagramReceived(internalClient.TcpClient, receivedBytes); |
||||
|
RaisePlaintextReceived(internalClient.TcpClient, receivedBytes); |
||||
|
|
||||
|
// continue listening for tcp datagram packets
|
||||
|
networkStream.BeginRead( |
||||
|
internalClient.Buffer, |
||||
|
0, |
||||
|
internalClient.Buffer.Length, |
||||
|
HandleDatagramReceived, |
||||
|
internalClient); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region Events
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 接收到数据报文事件
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived; |
||||
|
/// <summary>
|
||||
|
/// 接收到数据报文明文事件
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<TcpDatagramReceivedEventArgs<string>> PlaintextReceived; |
||||
|
|
||||
|
private void RaiseDatagramReceived(TcpClient sender, byte[] datagram) |
||||
|
{ |
||||
|
if (DatagramReceived != null) |
||||
|
{ |
||||
|
DatagramReceived(this, new TcpDatagramReceivedEventArgs<byte[]>(sender, datagram)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void RaisePlaintextReceived(TcpClient sender, byte[] datagram) |
||||
|
{ |
||||
|
if (PlaintextReceived != null) |
||||
|
{ |
||||
|
PlaintextReceived(this, new TcpDatagramReceivedEventArgs<string>( |
||||
|
sender, this.Encoding.GetString(datagram, 0, datagram.Length))); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 与客户端的连接已建立事件
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<TcpClientConnectedEventArgs> ClientConnected; |
||||
|
/// <summary>
|
||||
|
/// 与客户端的连接已断开事件
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<TcpClientDisconnectedEventArgs> ClientDisconnected; |
||||
|
|
||||
|
private void RaiseClientConnected(TcpClient tcpClient) |
||||
|
{ |
||||
|
if (ClientConnected != null) |
||||
|
{ |
||||
|
ClientConnected(this, new TcpClientConnectedEventArgs(tcpClient)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void RaiseClientDisconnected(TcpClient tcpClient) |
||||
|
{ |
||||
|
if (ClientDisconnected != null) |
||||
|
{ |
||||
|
ClientDisconnected(this, new TcpClientDisconnectedEventArgs(tcpClient)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region Send
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至指定的客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="tcpClient">客户端</param>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void Send(TcpClient tcpClient, byte[] datagram) |
||||
|
{ |
||||
|
if (!IsRunning) |
||||
|
throw new InvalidProgramException("This TCP server has not been started."); |
||||
|
|
||||
|
if (tcpClient == null) |
||||
|
throw new ArgumentNullException("tcpClient"); |
||||
|
|
||||
|
if (datagram == null) |
||||
|
throw new ArgumentNullException("datagram"); |
||||
|
|
||||
|
tcpClient.GetStream().BeginWrite( |
||||
|
datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient); |
||||
|
} |
||||
|
|
||||
|
private void HandleDatagramWritten(IAsyncResult ar) |
||||
|
{ |
||||
|
((TcpClient)ar.AsyncState).GetStream().EndWrite(ar); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至指定的客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="tcpClient">客户端</param>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void Send(TcpClient tcpClient, string datagram) |
||||
|
{ |
||||
|
Send(tcpClient, this.Encoding.GetBytes(datagram)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至所有客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void SendAll(byte[] datagram) |
||||
|
{ |
||||
|
if (!IsRunning) |
||||
|
throw new InvalidProgramException("This TCP server has not been started."); |
||||
|
|
||||
|
for (int i = 0; i < this.clients.Count; i++) |
||||
|
{ |
||||
|
Send(this.clients[i].TcpClient, datagram); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 发送报文至所有客户端
|
||||
|
/// </summary>
|
||||
|
/// <param name="datagram">报文</param>
|
||||
|
public void SendAll(string datagram) |
||||
|
{ |
||||
|
if (!IsRunning) |
||||
|
throw new InvalidProgramException("This TCP server has not been started."); |
||||
|
|
||||
|
SendAll(this.Encoding.GetBytes(datagram)); |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region IDisposable Members
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Performs application-defined tasks associated with freeing,
|
||||
|
/// releasing, or resetting unmanaged resources.
|
||||
|
/// </summary>
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
Dispose(true); |
||||
|
GC.SuppressFinalize(this); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Releases unmanaged and - optionally - managed resources
|
||||
|
/// </summary>
|
||||
|
/// <param name="disposing"><c>true</c> to release
|
||||
|
/// both managed and unmanaged resources; <c>false</c>
|
||||
|
/// to release only unmanaged resources.</param>
|
||||
|
protected virtual void Dispose(bool disposing) |
||||
|
{ |
||||
|
if (!this.disposed) |
||||
|
{ |
||||
|
if (disposing) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
Stop(); |
||||
|
|
||||
|
if (listener != null) |
||||
|
{ |
||||
|
listener = null; |
||||
|
} |
||||
|
} |
||||
|
catch (SocketException ex) |
||||
|
{ |
||||
|
ExceptionHandler.Handle(ex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
disposed = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
@ -1,186 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Data; |
|
||||
using System.Linq; |
|
||||
using System.Net; |
|
||||
using System.Net.Sockets; |
|
||||
using System.Text; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace DyeingComputer.UserClass |
|
||||
{ |
|
||||
public class TCPServer |
|
||||
{ |
|
||||
public static string infoR; |
|
||||
//第一步:调用socket()函数创建一个用于通信的套接字
|
|
||||
public static Socket listenSocket; |
|
||||
|
|
||||
//字典集合:存储IP和Socket的集合
|
|
||||
public static Dictionary<string, Socket> OnLineList = new Dictionary<string, Socket>(); |
|
||||
|
|
||||
|
|
||||
//当前时间
|
|
||||
private string CurrentTime |
|
||||
{ |
|
||||
get { return DateTime.Now.ToString("HH:mm:ss") + Environment.NewLine; } |
|
||||
} |
|
||||
|
|
||||
//编码格式
|
|
||||
public static Encoding econding = Encoding.UTF8; |
|
||||
|
|
||||
public static void Start() |
|
||||
{ |
|
||||
//第一步:调用socket()函数创建一个用于通信的套接字
|
|
||||
listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); |
|
||||
//第二步:给已经创建的套接字绑定一个端口号,这一般通过设置网络套接口地址和调用Bind()函数来实现
|
|
||||
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(UserClass.get_local_ip_address.IP_Address()), int.Parse("11080")); |
|
||||
UserClass.LogGing.LogGingDATA("NativeIP = " + UserClass.get_local_ip_address.IP_Address()); |
|
||||
UserClass.LogGing.LogGingDATA("NativePORT = 11080"); |
|
||||
try |
|
||||
{ |
|
||||
listenSocket.Bind(endPoint); |
|
||||
} |
|
||||
catch (Exception ex) |
|
||||
{ |
|
||||
UserClass.LogGing.LogGingDATA("TCP_NotStart"); |
|
||||
UserClass.LogGing.LogGingDATA(ex.Message); |
|
||||
return; |
|
||||
} |
|
||||
//第三步:调用listen()函数使套接字成为一个监听套接字
|
|
||||
listenSocket.Listen(10); |
|
||||
//ShowMessage("服务器开启成功");
|
|
||||
|
|
||||
//开启一个线程监听
|
|
||||
Task.Run(new Action(() => { ListenConnection(); })); |
|
||||
} |
|
||||
|
|
||||
public static void ListenConnection() |
|
||||
{ |
|
||||
while (true) |
|
||||
{ |
|
||||
Socket clientSocket = listenSocket.Accept(); |
|
||||
string ip = clientSocket.RemoteEndPoint.ToString(); |
|
||||
//更新在线列表
|
|
||||
// AddOnLine(ip, true);
|
|
||||
//更新在线列表集合
|
|
||||
OnLineList.Add(ip, clientSocket); |
|
||||
UserClass.LogGing.LogGingDATA("IP_Online = " + ip); |
|
||||
// ShowMessage(ip + "上线了");
|
|
||||
Task.Run(() => ReceiveMsg(clientSocket)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// 接收方法
|
|
||||
/// </summary>
|
|
||||
/// <param name="clientSocket"></param>
|
|
||||
public static void ReceiveMsg(Socket clientSocket) |
|
||||
{ |
|
||||
while (true) |
|
||||
{ |
|
||||
//定义一个2M的缓冲区
|
|
||||
byte[] buffer = new byte[1024 * 1024 * 10]; |
|
||||
|
|
||||
int length = -1; |
|
||||
try |
|
||||
{ |
|
||||
length = clientSocket.Receive(buffer); |
|
||||
} |
|
||||
catch (Exception) |
|
||||
{ |
|
||||
//客户端下线了
|
|
||||
//更新在线列表
|
|
||||
string ip = clientSocket.RemoteEndPoint.ToString(); |
|
||||
UserClass.LogGing.LogGingDATA("IP_Line = " + ip); |
|
||||
// AddOnLine(ip, false);
|
|
||||
OnLineList.Remove(ip); //移除ip
|
|
||||
break; //退出循环
|
|
||||
} |
|
||||
|
|
||||
if (length == 0) |
|
||||
{ |
|
||||
//客户端下线了
|
|
||||
//更新在线列表
|
|
||||
string ip = clientSocket.RemoteEndPoint.ToString(); |
|
||||
UserClass.LogGing.LogGingDATA("IP_Line = " + ip); |
|
||||
// AddOnLine(ip, false);
|
|
||||
OnLineList.Remove(ip); |
|
||||
break; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
infoR = econding.GetString(buffer, 0, length); |
|
||||
//ShowMessage(info);
|
|
||||
string ip = clientSocket.RemoteEndPoint.ToString(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
/* |
|
||||
/// <summary>
|
|
||||
/// 在线列表更新
|
|
||||
/// </summary>
|
|
||||
/// <param name="clientIp"></param>
|
|
||||
/// <param name="value"></param>
|
|
||||
private void AddOnLine(string clientIp, bool value) |
|
||||
{ |
|
||||
Invoke(new Action(() => |
|
||||
{ |
|
||||
if (value) |
|
||||
{ |
|
||||
this.lst_Online.Items.Add(clientIp); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
this.lst_Online.Items.Remove(clientIp); |
|
||||
} |
|
||||
|
|
||||
})); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
|
|
||||
/// <summary>
|
|
||||
/// 更新接收区
|
|
||||
/// </summary>
|
|
||||
/// <param name="info"></param>
|
|
||||
private void ShowMessage(string info) |
|
||||
{ |
|
||||
Invoke(new Action(() => |
|
||||
{ |
|
||||
this.txt_Rcv.AppendText(CurrentTime + info + Environment.NewLine); |
|
||||
})); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
*/ |
|
||||
/// <summary>
|
|
||||
/// 消息发送
|
|
||||
/// </summary>
|
|
||||
public static void Bn_Send(string IP, string DAT) |
|
||||
{ |
|
||||
if (OnLineList.ContainsKey(IP)) |
|
||||
{ |
|
||||
OnLineList[IP].Send(econding.GetBytes(DAT)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// 群发功能
|
|
||||
/// </summary>
|
|
||||
public static void Btn_SendAll(string DAT) |
|
||||
{ |
|
||||
foreach (string item in OnLineList.Keys.ToArray()) |
|
||||
{ |
|
||||
if (OnLineList.ContainsKey(item)) |
|
||||
{ |
|
||||
OnLineList[item].Send(econding.GetBytes(DAT)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
Loading…
Reference in new issue