用System.Net.Sockets.Socket类实现tcp通信并不简单,需要大量代码去实现,但其接近底层而可以发挥更高的效率,本文的目标是实现高性能的套接字客户端,否则没有使用Socket的必要,而应该使用更为简单易用的System.Net.Sockets.TcpClient
首先是参考资料,第一当然是微软的文档(https://docs.microsoft.com/zh-cn/dotnet/api/system.net.sockets.socket?view=netcore-3.1),其次是其他人写的代码https://www.iteye.com/blog/freshflower-2285286(C#SocketAsyncEventArgs实现高效能多并发TCPSocket通信 (客户端实现),有没有觉得本文的标题很像这篇文章?其实不然,本文采用与该作者不同的思路去写,实际代码完全不同,有雷同部分只是必须这么写而已。
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace CommonCode.CCnetwork {
public class CCSocketClient {
public delegate void OnConnectedEvent(bool connected);
public delegate void OnReceivePackageEvent(int signal, byte[] buffer);
public delegate void OnConnectionBreakEvent();
public delegate void OnSocketExceptionEvent(SocketException socketException);
public OnConnectedEvent onConnectedEvent;
public OnReceivePackageEvent onReceivePackageEvent;
public OnConnectionBreakEvent onConnectionBreakEvent;
public OnSocketExceptionEvent onSocketExceptionEvent;
private Socket socket;
private readonly SocketAsyncEventArgs receiveEventArgs;
private readonly SocketAsyncEventArgs[] sendEventArgs = new SocketAsyncEventArgs[] { new SocketAsyncEventArgs(), new SocketAsyncEventArgs() };
private readonly byte[] recvBuffer = new byte[255];
private readonly byte[] sendBuffer = new byte[255];
private readonly List<byte> recvData = new List<byte>();
private readonly List<byte> sendData = new List<byte>();
private byte state = 0;
public CCSocketClient() {
if (!Socket.OSSupportsIPv4) {
throw new NotSupportedException("系统不支持IPv4网络!");
}
receiveEventArgs = new SocketAsyncEventArgs();
receiveEventArgs.SetBuffer(recvBuffer, 0, recvBuffer.Length);
receiveEventArgs.Completed += ReceiveEventArgs_Completed;
sendEventArgs[0].Completed += SendEventArgs_Completed; ;
sendEventArgs[1].Completed += SendEventArgs_Completed; ;
}
public void Connect(string host, int port) {
try {
IPHostEntry entry = Dns.GetHostEntry(host);
if (entry != null && entry.AddressList != null) {
for (int AddressListIndex = 0; AddressListIndex < entry.AddressList.Length; AddressListIndex++) {
if (entry.AddressList[AddressListIndex].AddressFamily == AddressFamily.InterNetwork) {
socket?.Close();
socket?.Dispose();
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Soc