243 lines
7.8 KiB
C#
243 lines
7.8 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Net.Sockets;
|
|||
|
|
using System.Net;
|
|||
|
|
|
|||
|
|
namespace SimpleServer
|
|||
|
|
{
|
|||
|
|
public class Client : IDisposable
|
|||
|
|
{
|
|||
|
|
#region DataMember & Ctor
|
|||
|
|
private 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<byte[]> RecvMsgEvent;
|
|||
|
|
public event DlgOneParam<string> RemoteDisconnectEvent;
|
|||
|
|
public event DlgNoParam LocalDisconnectEvent;
|
|||
|
|
|
|||
|
|
/// <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(byte[] msg)
|
|||
|
|
{
|
|||
|
|
bool result = false;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
netstream.Write(msg, 0, msg.Length);
|
|||
|
|
result = true;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
catch
|
|||
|
|
{
|
|||
|
|
throw;
|
|||
|
|
}
|
|||
|
|
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
|
|||
|
|
{
|
|||
|
|
int count = netstream.EndRead(ar);
|
|||
|
|
if (count > 0)
|
|||
|
|
{
|
|||
|
|
string recvStr = Encoding.Default.GetString(readBytes, 0, count);
|
|||
|
|
recvStr = recvStr + "\r\n\r\n";
|
|||
|
|
if (RecvMsgEvent != null)
|
|||
|
|
{
|
|||
|
|
RecvMsgEvent(readBytes);
|
|||
|
|
}
|
|||
|
|
readBytes = new byte[tcpclient.ReceiveBufferSize];
|
|||
|
|
netstream.BeginRead(readBytes, 0, readBytes.Length, EndRead, null);
|
|||
|
|
}
|
|||
|
|
else//远程客户端主动断开
|
|||
|
|
{
|
|||
|
|
LocalClientClose();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
if (ex.Message.Contains("无法从传输连接中读取数据: 远程主机强迫关闭了一个现有的连接"))
|
|||
|
|
{
|
|||
|
|
LocalClientClose();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
throw;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 客户端连接和关闭
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 客户端的client连接服务器
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="ip"></param>
|
|||
|
|
/// <param name="port"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public bool Connect(string ip, string port)
|
|||
|
|
{
|
|||
|
|
bool result = false;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
ip = ip.Trim();
|
|||
|
|
port = port.Trim();
|
|||
|
|
if (!string.IsNullOrEmpty(ip) && !string.IsNullOrEmpty(port))
|
|||
|
|
{
|
|||
|
|
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();
|
|||
|
|
closed = false;
|
|||
|
|
result = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
if (ex.Message.Contains("由于目标机器积极拒绝,无法连接"))
|
|||
|
|
{
|
|||
|
|
if (ConnectFailEvent != null)
|
|||
|
|
{
|
|||
|
|
ConnectFailEvent();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 远程连接断开后(点关闭断开,程序退出断开)本地连接处理
|
|||
|
|
/// </summary>
|
|||
|
|
private 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
|
|||
|
|
}
|
|||
|
|
}
|