280 lines
9.0 KiB
C#
280 lines
9.0 KiB
C#
using System;
|
|||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Text;
|
||
|
|
using System.Net.Sockets;
|
||
|
|
using System.Net;
|
||
|
|
using System.Windows.Forms;
|
||
|
|
|
||
|
|
namespace SimpleCommunication
|
||
|
|
{
|
||
|
|
public class Client : IDisposable
|
||
|
|
{
|
||
|
|
#region DataMember & Ctor
|
||
|
|
public TcpClient tcpclient;
|
||
|
|
private NetworkStream netstream;
|
||
|
|
public string IP;
|
||
|
|
public string Port;
|
||
|
|
private byte[] readBytes;
|
||
|
|
private object tcpClientLock = new object();//锁TcpClient;Dispose之后就不允许EndRead,远程连接断开以后,就不允许再调用Dispose
|
||
|
|
private bool closed = false;//包括本地主动断开和远程断开
|
||
|
|
|
||
|
|
//在事务处理结束后才触发下列事件
|
||
|
|
public event DlgNoParam ConnectFailEvent;
|
||
|
|
public event DlgOneParam<string> NewClientEvent;
|
||
|
|
public event DlgOneParam<string> RecvMsgEvent;
|
||
|
|
public event DlgOneParam<string> RemoteDisconnectEvent;
|
||
|
|
public event DlgNoParam LocalDisconnectEvent;
|
||
|
|
/// <summary>
|
||
|
|
/// 客户端是否链接
|
||
|
|
/// </summary>
|
||
|
|
public bool IsConnected => (tcpclient != null && tcpclient.Connected) ? true : false;
|
||
|
|
/// <summary>
|
||
|
|
/// 服务的client的构造函数
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="tcpclient"></param>
|
||
|
|
public Client(TcpClient tcpclient)
|
||
|
|
{
|
||
|
|
this.tcpclient = tcpclient;
|
||
|
|
readBytes = new byte[tcpclient.ReceiveBufferSize];//接收数据的缓冲区大小,如果太小一段数据会多次接收完成
|
||
|
|
netstream = tcpclient.GetStream();//如果远程客户端断开一样可以获得netstream
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 客户端client的构造函数
|
||
|
|
/// </summary>
|
||
|
|
public Client()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region 数据收发
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 在建立连接的情况下发送消息
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="msg"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool SendMsg(string msg)
|
||
|
|
{
|
||
|
|
bool result = false;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (netstream != null)
|
||
|
|
{
|
||
|
|
if (!string.IsNullOrEmpty(msg))
|
||
|
|
{
|
||
|
|
byte[] buff = Encoding.Default.GetBytes(msg);
|
||
|
|
netstream.Write(buff, 0, buff.Length);
|
||
|
|
|
||
|
|
|
||
|
|
result = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
throw ex;
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 服务的接收到客户端连接后最先做的操作之一,客户端接收数据线程起始
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool BeginRead()
|
||
|
|
{
|
||
|
|
bool result = false;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
IP = (tcpclient.Client.RemoteEndPoint as IPEndPoint).Address.ToString();
|
||
|
|
Port = (tcpclient.Client.RemoteEndPoint as IPEndPoint).Port.ToString();
|
||
|
|
if (NewClientEvent != null)
|
||
|
|
{
|
||
|
|
NewClientEvent(IP + " " + Port);
|
||
|
|
}
|
||
|
|
netstream.BeginRead(readBytes, 0, readBytes.Length, EndRead, null);//如果远程客户端断开这句话一样可以执行
|
||
|
|
result = true;
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
throw;
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 有互斥资源
|
||
|
|
/// 接收数据,远程连接断开,远程程序关闭,本地连接断开,都会按顺序调用进来;因为连接关闭后不再调用BeginRead
|
||
|
|
/// 服务器listener.stop时不会进入这个函数,客户端照样通讯,服务端只是不能接收新连接而已
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="ar"></param>
|
||
|
|
private void EndRead(IAsyncResult ar)
|
||
|
|
{
|
||
|
|
lock (tcpClientLock)
|
||
|
|
{
|
||
|
|
if (!closed)//如果本地主动断开就不会进入
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
string recvStr = "";
|
||
|
|
int count = netstream.EndRead(ar);
|
||
|
|
if (count > 0)
|
||
|
|
{
|
||
|
|
recvStr = Encoding.Default.GetString(readBytes, 0, count);
|
||
|
|
recvStr = DateTime.Now.ToString("HH:mm:ss") + " [" + IP + " " + Port + "] :\n" + recvStr + "\n";
|
||
|
|
if (RecvMsgEvent != null)
|
||
|
|
{
|
||
|
|
RecvMsgEvent(recvStr);
|
||
|
|
}
|
||
|
|
readBytes = new byte[tcpclient.ReceiveBufferSize];
|
||
|
|
netstream.BeginRead(readBytes, 0, readBytes.Length, EndRead, null);
|
||
|
|
}
|
||
|
|
else//远程客户端主动断开
|
||
|
|
{
|
||
|
|
LocalClientClose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
if (ex.Message.Contains("无法从传输连接中读取数据: 远程主机强迫关闭了一个现有的连接"))
|
||
|
|
{
|
||
|
|
LocalClientClose();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
LocalClientClose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region 客户端连接和关闭
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 客户端的client连接服务器
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="ip"></param>
|
||
|
|
/// <param name="port"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool Connect(ComboBox Server_IP, TextBox txtPort)
|
||
|
|
{
|
||
|
|
bool result = false;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
|
||
|
|
if (!string.IsNullOrEmpty(Server_IP.Text) && !string.IsNullOrEmpty(txtPort.Text))
|
||
|
|
{
|
||
|
|
IP = Server_IP.Text.Trim();
|
||
|
|
Port = txtPort.Text.Trim();
|
||
|
|
IPAddress ipAddress = IPAddress.Parse(IP);
|
||
|
|
IPEndPoint point = new IPEndPoint(ipAddress, int.Parse(Port));
|
||
|
|
tcpclient = new TcpClient(AddressFamily.InterNetwork);
|
||
|
|
readBytes = new byte[tcpclient.ReceiveBufferSize];
|
||
|
|
tcpclient.Connect(point);
|
||
|
|
|
||
|
|
netstream = tcpclient.GetStream();
|
||
|
|
BeginRead();
|
||
|
|
closed = false;
|
||
|
|
result = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
if (ex.Message.Contains("由于目标计算机积极拒绝"))
|
||
|
|
{
|
||
|
|
if (ConnectFailEvent != null)
|
||
|
|
{
|
||
|
|
ConnectFailEvent();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 远程连接断开后(点关闭断开,程序退出断开)本地连接处理
|
||
|
|
/// </summary>
|
||
|
|
public void LocalClientClose()
|
||
|
|
{
|
||
|
|
closed = true;
|
||
|
|
DisposeEx();
|
||
|
|
if (RemoteDisconnectEvent != null)
|
||
|
|
{
|
||
|
|
string param = IP + " " + Port;
|
||
|
|
if (RemoteDisconnectEvent != null)
|
||
|
|
{
|
||
|
|
RemoteDisconnectEvent(param);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 有互斥资源
|
||
|
|
/// 在已连接条件下关闭本地连接和资源释放时调用
|
||
|
|
/// </summary>
|
||
|
|
public void Dispose()
|
||
|
|
{
|
||
|
|
lock (tcpClientLock)
|
||
|
|
{
|
||
|
|
if (!closed)
|
||
|
|
{
|
||
|
|
closed = true;
|
||
|
|
DisposeEx();
|
||
|
|
if (LocalDisconnectEvent != null)
|
||
|
|
{
|
||
|
|
LocalDisconnectEvent();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 由Dispose和LocalClientClose调用
|
||
|
|
/// </summary>
|
||
|
|
private void DisposeEx()
|
||
|
|
{
|
||
|
|
if (netstream != null)
|
||
|
|
{
|
||
|
|
netstream.Dispose();
|
||
|
|
netstream = null;
|
||
|
|
}
|
||
|
|
if (tcpclient != null)
|
||
|
|
{
|
||
|
|
tcpclient.Close();
|
||
|
|
tcpclient = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <数据结构类>
|
||
|
|
/// 数据结构类
|
||
|
|
/// </数据结构类>
|
||
|
|
public class StateObject
|
||
|
|
{
|
||
|
|
//客户端Socket
|
||
|
|
public Socket workSocket = null;
|
||
|
|
//接收数据大小
|
||
|
|
public const int BufferSize = 64;
|
||
|
|
// 声明接收数据
|
||
|
|
public byte[] buffer = new byte[BufferSize];
|
||
|
|
// 接收数据的内容
|
||
|
|
public StringBuilder sb = new StringBuilder();
|
||
|
|
/// <summary>
|
||
|
|
/// 通信方网络地址
|
||
|
|
/// </summary>
|
||
|
|
public EndPoint SEndPoint;
|
||
|
|
}
|
||
|
|
}
|