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