17,740
社区成员
发帖
与我相关
我的任务
分享
namespace ServerWithBeat
{
class Program
{
const string IP = "192.168.1.22";
static void Main(string[] args)
{
Console.Title = "服务端启用Keep-alive机制";
MyTcpListener _tcpServer = new MyTcpListener(IPAddress.Parse(IP), 44818);
_tcpServer.Start();
Console.WriteLine("服务端启动,开始监听44818端口...");
Task _tListening = new Task(() =>
{
try
{
while (_tcpServer.Active)
{
TcpClient _tcpcClient = _tcpServer.AcceptTcpClient();
Console.WriteLine("客户端{0}:{1}已经接入。", (_tcpcClient.Client.RemoteEndPoint as IPEndPoint).Address, (_tcpcClient.Client.RemoteEndPoint as IPEndPoint).Port);
//接入一个客户端后,单独为其开启一个线程使服务端和客户端通信
Task.Run(() =>
{
#region 服务端设置Keep-alive心跳功能
_tcpcClient.Client.IOControl(IOControlCode.KeepAliveValues, GetKeepAliveData(), null);//设置Keep-alive参数
_tcpcClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);//启用Keep-alive
#endregion
#region 服务端Socket设置ReceiveTimeout选项来控制接受超时时间
_tcpcClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 60000);//设定60秒未接受到数据视为超时,超时后_stream.Read将异常,进入catch后执行close关闭socket
#endregion
#region 服务端socket设置SO_LINGER启用并设定超时时间为0,强制Close后发送RST包
//以下两种设置,都没有测试通过:服务端Close掉Socket后,wireshark都没有抓到RST包,只有在客户端再次Send时才看到了RST包
//_tcpcClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, 0));
//_tcpcClient.Client.LingerState = new LingerOption(true, 0);
_tcpcClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
#endregion
NetworkStream _stream = _tcpcClient.GetStream();
try
{
byte[] _data = Encoding.Default.GetBytes("欢迎,我是服务端!");
_stream.Write(_data, 0, _data.Length);
while ((_tcpServer.Active) && (_tcpcClient.Connected))
{
_data = new byte[1024];
int _len = _stream.Read(_data, 0, 1024);
if (_len == 0)
break;
Console.WriteLine("来自客户端{0}:{1}:{2}", (_tcpcClient.Client.RemoteEndPoint as IPEndPoint).Address, (_tcpcClient.Client.RemoteEndPoint as IPEndPoint).Port, Encoding.Default.GetString(_data, 0, _len));
if ("killme" == Encoding.Default.GetString(_data, 0, _len))
break;
}
Console.WriteLine("客户端{0}:{1}断开连接。", (_tcpcClient.Client.RemoteEndPoint as IPEndPoint).Address, (_tcpcClient.Client.RemoteEndPoint as IPEndPoint).Port);
_stream.Close();
_tcpcClient.Close();
}
catch(Exception ex)
{
Console.WriteLine("客户端连接异常:" + ex.Message);
try
{
_stream.Close();
_tcpcClient.Close();
}
catch { }
}
});
}
}
catch(Exception ex)
{
Console.WriteLine("服务端连接异常:" + ex.Message);
}
});
_tListening.Start();
Console.ReadKey();
_tcpServer.Stop();
_tListening.Wait();
//Task.WaitAll();
Console.WriteLine("服务端停止,按任意键关闭程序。");
Console.ReadKey();
}
static byte[] GetKeepAliveData()
{
uint dummy = 0;
byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
//启用KeepaliveValue功能
BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);
//连接空闲5秒后开始发送心跳包
BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy));
BitConverter.GetBytes((uint)500).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);
return inOptionValues;
}
}
//定义一个TcpListener子类,开放出TcpListener protected的Active属性
class MyTcpListener : TcpListener
{
public MyTcpListener(IPEndPoint localEP) : base(localEP)
{
}
public MyTcpListener(int port) : base(port)
{
}
public MyTcpListener(IPAddress localaddr, int port) : base(localaddr, port)
{
}
public new bool Active
{
get
{
return base.Active;
}
}
}
namespace ClientNoBeat
{
class Program
{
const string IP = "192.168.1.22";
static void Main(string[] args)
{
Console.Title = "客户端没有启用Keep-alive机制";
TcpClient _tcpClient = new TcpClient(IP, 44818);
Console.WriteLine("已连接到服务器192.168.1.22:44818,本地端口" + (_tcpClient.Client.LocalEndPoint as IPEndPoint).Address + ":" + (_tcpClient.Client.LocalEndPoint as IPEndPoint).Port);
NetworkStream _stream = _tcpClient.GetStream();
byte[] _buff = new byte[1024];
int _len = _stream.Read(_buff, 0, 1024);
Console.WriteLine(Encoding.Default.GetString(_buff, 0, _len));
while (_tcpClient.Connected)
{
string _msg = Console.ReadLine();
if ("exit" == _msg)
break;
byte[] _data = Encoding.Default.GetBytes(_msg);
_stream.Write(_data, 0, _data.Length);
}
_stream.Close();
_tcpClient.Close();
Console.WriteLine("与服务端连接已断开,按任意键结束程序。");
Console.ReadKey();
}
}
}