之所以要进行Socket套接字通信库封装,主要是直接使用套接字进行网络通信编程相对复杂,特别对于初学者而言。实际上微软从.net 2.0开始已经提供了TCP、UDP通信高级封装类如下:
TcpListener
TcpClient
UdpClient
微软从.net 4.0开始提供基于Task任务的异步通信接口。而直接使用socket封装库,很多socket本身的细节没办法自行控制,本文目就是提供一种socket的封装供参考。文中展示部分封装了TCP通信库,UDP封装也可触类旁通:
CusTcpListener
CusTcpClient
TCP服务端封装了服务端本地绑定、监听、接受客户端连接,并提供了网络数据流的接口。完整代码:
public class CusTcpListener
{
private IPEndPoint mServerSocketEndPoint;
private Socket mServerSocket;
private bool isActive;
public Socket Server
{
get { return this.mServerSocket; }
}
protected bool Active
{
get { return this.isActive; }
}
public EndPoint LocalEndpoint
{
get
{
if (!this.isActive)
{
return this.mServerSocketEndPoint;
}
return this.mServerSocket.LocalEndPoint;
}
}
public NetworkStream DataStream
{
get
{
NetworkStream networkStream = null;
if (this.Server.Connected)
{
networkStream = new NetworkStream(this.Server, true);
}
return networkStream;
}
}
public CusTcpListener(IPEndPoint localEP)
{
this.mServerSocketEndPoint = localEP;
this.mServerSocket = new Socket(this.mServerSocketEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public CusTcpListener(string localaddr, int port)
{
if (localaddr == null)
{
throw new ArgumentNullException("localaddr");
}
this.mServerSocketEndPoint = new IPEndPoint(IPAddress.Parse(localaddr), port);
this.mServerSocket = new Socket(this.mServerSocketEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public CusTcpListener(int port)
{
this.mServerSocketEndPoint = new IPEndPoint(IPAddress.Any, port);
this.mServerSocket = new Socket(this.mServerSocketEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public void Start()
{
this.Start(int.MaxValue);
}
///
/// 开始服务器监听
///
/// 同时等待连接的最大个数(半连接队列个数限制)
public void Start(int backlog)
{
if (backlog > int.MaxValue || backlog < 0)
{
throw new ArgumentOutOfRangeException("backlog");
}
if (this.mServerSocket == null)
{
throw new NullReferenceException("套接字为空");
}
this.mServerSocket.Bind(this.mServerSocketEndPoint);
this.mServerSocket.Listen(backlog);
this.isActive = true;
}
public void Stop()
{
if (this.mServerSocket != null)
{
this.mServerSocket.Close();
this.mServerSocket = null;
}
this.isActive = false;
this.mServerSocket = new Socket(this.mServerSocketEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
public Socket AcceptSocket()
{
Socket socket = this.mServerSocket.Accept();
return socket;
}
public CusTcpClient AcceptTcpClient()
{
CusTcpClient tcpClient = new CusTcpClient(this.mServerSocket.Accept());
return tcpClient;
}
}
TCP客户端封装了客户端本地绑定、连接服务器,并提供了网络数据流的接口。完整代码:
public class CusTcpClient : IDisposable
{
public Socket Client { get; set; }
protected bool Active { get; set; }
public IPEndPoint ClientSocketEndPoint { get; set; }
public bool IsConnected { get { return this.Client.Connected; } }
public NetworkStream DataStream
{
get
{
NetworkStream networkStream = null;
if (this.Client.Connected)
{
networkStream = new NetworkStream(this.Client, true);
}
return networkStream;
}
}
public CusTcpClient(IPEndPoint localEP)
{
if (localEP == null)
{
throw new ArgumentNullException("localEP");
}
this.Client = new Socket(localEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
this.Active = false;
this.Client.Bind(localEP);
this.ClientSocketEndPoint = localEP;
}
public CusTcpClient(string localaddr, int port)
{
if (localaddr == null)
{
throw new ArgumentNullException("localaddr");
}
IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(localaddr), port);
this.Client = new Socket(localEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
this.Active = false;
this.Client.Bind(localEP);
this.ClientSocketEndPoint = localEP;
}
internal CusTcpClient(Socket acceptedSocket)
{
this.Client = acceptedSocket;
this.Active = true;
this.ClientSocketEndPoint = (IPEndPoint)this.Client.LocalEndPoint;
}
public void Connect(string address, int port)
{
if (address == null)
{
throw new ArgumentNullException("address");
}
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(address), port);
this.Connect(remoteEP);
}
public void Connect(IPEndPoint remoteEP)
{
if (remoteEP == null)
{
throw new ArgumentNullException("remoteEP");
}
this.Client.Connect(remoteEP);
this.Active = true;
}
public void Close()
{
this.Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
IDisposable dataStream = this.DataStream;
if (dataStream != null)
{
dataStream.Dispose();
}
else
{
Socket client = this.Client;
if (client != null)
{
client.Close();
this.Client = null;
}
}
GC.SuppressFinalize(this);
}
}
public void Dispose()
{
this.Dispose(true);
}
}
控制台程序试验,服务端程序:
class Program
{
static void Main(string[] args)
{
Thread listenerThread = new Thread(ListenerClientConnection);
listenerThread.IsBackground = true;
listenerThread.Start();
Console.ReadKey();
}
private static void ListenerClientConnection()
{
CusTcpListener tcpListener = new CusTcpListener("127.0.0.1", 5100);
tcpListener.Start();
Console.WriteLine("等待客户端连接……");
while (true)
{
CusTcpClient tcpClient = tcpListener.AcceptTcpClient();
Console.WriteLine("客户端接入,ip={0} port={1}",
tcpClient.ClientSocketEndPoint.Address, tcpClient.ClientSocketEndPoint.Port);
Thread thread = new Thread(DataHandleProcess);
thread.IsBackground = true;
thread.Start(tcpClient);
}
}
private static void DataHandleProcess(object obj)
{
CusTcpClient tcpClient = (CusTcpClient)obj;
StreamReader streamReader = new StreamReader(tcpClient.DataStream, Encoding.Default);
Console.WriteLine("等待客户端输入:");
while (true)
{
try
{
string receStr = streamReader.ReadLine();
Console.WriteLine(receStr);
}
catch (Exception)
{
Console.WriteLine("断开连接");
break;
}
Thread.Sleep(5);
}
}
}
客户端程序:
class Program
{
static void Main(string[] args)
{
Thread listenerThread = new Thread(UserProcess);
listenerThread.IsBackground = true;
listenerThread.Start();
Console.ReadKey();
}
private static void UserProcess()
{
Console.WriteLine("连接服务器");
CusTcpClient tcpClient = new CusTcpClient("127.0.0.1", 5080);
tcpClient.Connect("127.0.0.1", 5100);
Console.WriteLine("开始和服务器通信");
StreamWriter sw = new StreamWriter(tcpClient.DataStream, Encoding.Default);
sw.AutoFlush = true;
while (true)
{
for (int i = 0; i < 10; i++)
{
string str = string.Format("第{0}次,内容:{1}", i, "测试通信");
Console.WriteLine("发送数据:{0}", str);
sw.WriteLine(str);
}
break;
}
}
}
通信成功:
通过本次封装演示可实现基于Socket的通信库封装,目的就是使用Socket通信库让应用开发人员在进行网络通讯编程时无需关心底层通讯机制,而只关心应用层的开发,让开发变得更简洁。当然UDP封装类似,可自行设计。当然本文只是一种示例,实际使用可使用.net自带封装库或自定义封装。
补充:目前有很多优秀的开源Socket框架,比如SuperSocket、FastSocket等。