C#使用SocketAsyncEventArgs实现Socket客户端通信

本文介绍如何使用C#的SocketAsyncEventArgs实现高性能的TCP套接字客户端,强调异步连接和线程安全的SendPackage方法。详细讨论了连接、发送数据和接收数据的机制,并提供了处理回调事件的建议,以避免丢包和性能问题。
摘要由CSDN通过智能技术生成

用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
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的C# Socket服务端使用SocketAsyncEventArgs的示例代码: ```csharp using System; using System.Net; using System.Net.Sockets; using System.Threading; public class SocketServer { private Socket m_serverSocket; private Semaphore m_maxAcceptedClients; private SocketAsyncEventArgsPool m_readWritePool; public SocketServer(int maxConnections) { m_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); m_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 1234)); m_serverSocket.Listen(maxConnections); m_maxAcceptedClients = new Semaphore(maxConnections, maxConnections); m_readWritePool = new SocketAsyncEventArgsPool(maxConnections); for (int i = 0; i < maxConnections; i++) { SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs(); readEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed); readEventArgs.UserToken = new AsyncUserToken(); m_readWritePool.Push(readEventArgs); } } public void Start() { StartAccept(null); } private void StartAccept(SocketAsyncEventArgs acceptEventArgs) { if (acceptEventArgs == null) { acceptEventArgs = new SocketAsyncEventArgs(); acceptEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(Accept_Completed); } else { acceptEventArgs.AcceptSocket = null; } m_maxAcceptedClients.WaitOne(); if (!m_serverSocket.AcceptAsync(acceptEventArgs)) { ProcessAccept(acceptEventArgs); } } private void ProcessAccept(SocketAsyncEventArgs acceptEventArgs) { SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop(); AsyncUserToken userToken = (AsyncUserToken)readEventArgs.UserToken; userToken.Socket = acceptEventArgs.AcceptSocket; userToken.ReadEventArgs = readEventArgs; readEventArgs.AcceptSocket = userToken.Socket; if (!userToken.Socket.ReceiveAsync(readEventArgs)) { ProcessReceive(readEventArgs); } StartAccept(acceptEventArgs); } private void Accept_Completed(object sender, SocketAsyncEventArgs e) { ProcessAccept(e); } private void IO_Completed(object sender, SocketAsyncEventArgs e) { switch (e.LastOperation) { case SocketAsyncOperation.Receive: ProcessReceive(e); break; case SocketAsyncOperation.Send: ProcessSend(e); break; default: throw new ArgumentException("The last operation completed on the socket was not a receive or send"); } } private void ProcessReceive(SocketAsyncEventArgs e) { AsyncUserToken userToken = (AsyncUserToken)e.UserToken; if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { userToken.Data.AddRange(e.Buffer.Take(e.BytesTransferred)); if (userToken.Data.Count >= 4) { int len = BitConverter.ToInt32(userToken.Data.Take(4).ToArray(), 0); if (userToken.Data.Count >= 4 + len) { byte[] buffer = userToken.Data.Skip(4).Take(len).ToArray(); userToken.Data.RemoveRange(0, 4 + len); // 处理请求并响应 byte[] response = HandleRequest(buffer); Send(userToken.Socket, response); return; } } if (!userToken.Socket.ReceiveAsync(e)) { ProcessReceive(e); } } else { CloseClientSocket(userToken); } } private void ProcessSend(SocketAsyncEventArgs e) { AsyncUserToken userToken = (AsyncUserToken)e.UserToken; if (e.SocketError == SocketError.Success) { if (!userToken.Socket.ReceiveAsync(userToken.ReadEventArgs)) { ProcessReceive(userToken.ReadEventArgs); } } else { CloseClientSocket(userToken); } } private void Send(Socket socket, byte[] buffer) { SocketAsyncEventArgs sendEventArgs = new SocketAsyncEventArgs(); sendEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed); sendEventArgs.SetBuffer(buffer, 0, buffer.Length); sendEventArgs.UserToken = socket; if (!socket.SendAsync(sendEventArgs)) { ProcessSend(sendEventArgs); } } private void CloseClientSocket(AsyncUserToken userToken) { try { userToken.Socket.Shutdown(SocketShutdown.Send); } catch (Exception) { } userToken.Socket.Close(); m_readWritePool.Push(userToken.ReadEventArgs); m_maxAcceptedClients.Release(); } private byte[] HandleRequest(byte[] request) { // 处理请求并响应 return null; } } public class AsyncUserToken { public Socket Socket { get; set; } public List<byte> Data { get; set; } public SocketAsyncEventArgs ReadEventArgs { get; set; } public AsyncUserToken() { Data = new List<byte>(); } } ``` 以上示例代码演示了如何使用SocketAsyncEventArgs实现一个简单的Socket服务端,其中包含了异步接收、异步发送和连接池等功能。当有客户端连接时,它会从连接池中获取一个SocketAsyncEventArgs对象,并使用它来进行通信。在通信完成后,它会将SocketAsyncEventArgs对象放回连接池中,以便于重用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值