GJM : Socket TCP 通信连接(三)
上一篇中,我们编写了SocketHandler处理Socket的IO。
现在我们只剩下服务器端了。
服务器端包含两个类,一个TCPListener,一个TCPListenerClient。
TCPListener只管Start与Stop还有Accept。
TCPListenerClient是连接到服务器的客户端,相当于TCPClient在TCPListener上的体现。
现在我们开始编写TCPListener。
/// <summary>
/// TCP监听端
/// </summary>
public class TCPListener : IEnumerable<TCPListenerClient>
{
private Socket socket;
private HashSet<TCPListenerClient> clients;
/// <summary>
/// 实例化TCP监听者。
/// </summary>
public TCPListener()
{
clients = new HashSet<TCPListenerClient>();
IsStarted = false;
Handler = new SocketHandler();
}
public ISocketHandler Handler { get; set; }
private int port;
/// <summary>
/// 监听端口。
/// </summary>
public int Port
{
get { return port; }
set
{
if (value < 0 || value > 65535)
throw new ArgumentOutOfRangeException(port + "不是有效端口。");
port = value;
}
}
/// <summary>
/// 服务启动中
/// </summary>
public bool IsStarted { get; private set; }
/// <summary>
/// 开始服务。
/// </summary>
public void Start()
{
}
/// <summary>
/// 停止服务。
/// </summary>
public void Stop()
{
}
/// <summary>
/// 接收完成时引发事件。
/// </summary>
public event EventHandler<SocketEventArgs> ReceiveCompleted;
/// <summary>
/// 接受客户完成时引发事件。
/// </summary>
public event EventHandler<SocketEventArgs> AcceptCompleted;
/// <summary>
/// 客户断开完成时引发事件。
/// </summary>
public event EventHandler<SocketEventArgs> DisconnectCompleted;
/// <summary>
/// 发送完成时引发事件。
/// </summary>
public event EventHandler<SocketEventArgs> SendCompleted;
/// <summary>
/// 获取客户端泛型。
/// </summary>
/// <returns></returns>
public IEnumerator<TCPListenerClient> GetEnumerator()
{
return clients.GetEnumerator();
}
/// <summary>
/// 获取客户端泛型。
/// </summary>
/// <returns></returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return clients.GetEnumerator();
}
/// <summary>
/// 释放资源。
/// </summary>
/// <returns></returns>
public void Dispose()
{
}
}
TCPListener继承IEnumerable<TCPListenerClient>与IDisposable
clients保存所有已连接的客户端。
编写Start方法。
/// <summary>
/// 开始服务。
/// </summary>
public void Start()
{
lock (this)
{
if (IsStarted)
throw new InvalidOperationException("已经开始服务。");
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定端口
//可以引发端口被占用异常
socket.Bind(new IPEndPoint(IPAddress.Any, port));
//监听队列
socket.Listen(512);
//如果端口是0,则是随机端口,把这个端口赋值给port
port = ((IPEndPoint)socket.LocalEndPoint).Port;
//服务启动中设置为true
IsStarted = true;
//开始异步监听
socket.BeginAccept(EndAccept, null);
}
}
//异步监听结束
private void EndAccept(IAsyncResult result)
{
//获得客户端Socket
Socket clientSocket = socket.EndAccept(result);
//实例化客户端类
TCPListenerClient client = new TCPListenerClient(this, clientSocket);
//增加事件钩子
client.SendCompleted += client_SendCompleted;
client.ReceiveCompleted += client_ReceiveCompleted;
client.DisconnectCompleted += client_DisconnectCompleted;
socket.BeginAccept(EndAccept, null);
//增加客户端
lock (clients)
clients.Add(client);
//客户端连接事件
if (AcceptCompleted != null)
AcceptCompleted(this, new SocketEventArgs(client, SocketAsyncOperation.Accept));
}
//客户端断开连接
private void client_DisconnectCompleted(object sender, SocketEventArgs e)
{
//移除客户端
lock (clients)
clients.Remove((TCPListenerClient)e.Socket);
e.Socket.DisconnectCompleted -= client_DisconnectCompleted;
e.Socket.ReceiveCompleted -= client_ReceiveCompleted;
e.Socket.SendCompleted -= client_SendCompleted;
if (DisconnectCompleted != null)
DisconnectCompleted(this, e);
}
//收到客户端发送的数据
private void client_ReceiveCompleted(object sender, SocketEventArgs e)
{
if (ReceiveCompleted != null)
ReceiveCompleted(this, e);
}
//向客户端发送数据完成
private void client_SendCompleted(object sender, SocketEventArgs e)
{
if (SendCompleted != null)
SendCompleted(this, e);
}
编写Stop与Dispose方法。
/// <summary>
/// 停止服务。
/// </summary>
public void Stop()
{
lock (this)
{
if (!IsStarted)
throw new InvalidOperationException("没有开始服务。");
foreach (TCPListenerClient client in clients)
{
client.Disconnect();
client.DisconnectCompleted -= client_DisconnectCompleted;
client.ReceiveCompleted -= client_ReceiveCompleted;
client.SendCompleted -= client_SendCompleted;
}
socket.Close();
socket = null;
IsStarted = false;
}
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
if (socket == null)
return;
Stop();
}
轮到TCPListenerClient了,TCPListenerClient其实和TCPClient差不多,也是要继承ISocket和IDisposable。
既然重复代码做么多,要不要合并起来呢?答案是肯定的。
做一个SocketBase类,继承ISocket和IDisposable。
大部分代码直接从TCPClient复制过来。
View Code然后我们再写TCPListenerClient,继承SocketBase。
public class TCPListenerClient : SocketBase
{
internal TCPListenerClient(TCPListener listener, Socket socket)
:base(socket,listener.Handler)
{
this["RemoteEndPoint"] = socket.RemoteEndPoint;
//创建Socket网络流
Stream = new NetworkStream(socket);
//设置服务器
Listener = listener;
data = new Dictionary<string, object>();
//开始异步接收数据
SocketAsyncState state = new SocketAsyncState();
Handler.BeginReceive(Stream, EndReceive, state);
}
public TCPListener Listener { get; private set; }
}
我们还可以给TCPListenerClient加上点东西,比如类似Session的东西。
private Dictionary<string, object> data;
public object this[string key]
{
get
{
key = key.ToLower();
if (data.ContainsKey(key))
return data[key];
return null;
}
set
{
key = key.ToLower();
if (value == null)
{
if (data.ContainsKey(key))
data.Remove(key);
return;
}
if (data.ContainsKey(key))
data[key] = value;
else
data.Add(key, value);
}
}
为构造函数添加以下代码。
data = new Dictionary<string, object>();
//保存IP地址到字典
this["RemoteEndPoint"] = socket.RemoteEndPoint;
这样,我们的TCPListenerClient就完成了。
接下来我们再把TCPClient修改以下,继承SocketBase。
View Code所有工作,全部完成。
这个Socket还有很多功能可以增加、改造。
比如你自己写一个Handler内置加密解密,或者压缩与解压缩。
还可以再改写一下Stream,可以弄成NegotiateStream验证等等。
下一篇我们总结一下所有工作。
原文地址:http://www.cnblogs.com/Kation/archive/2013/03/07/2947278.html


浙公网安备 33010602011771号