C#中Socket编程,异步实现Server端定时发送消息
在最近项目需求中,要求服务端定时向客服端发送消息。由于客户端从机的特性,只能接收Server发送的消息后回复,不能主动向服务端发送消息。
起初,并未使用异步的方法进行编程,使用了Accept()、Revice()等方法。由于从机不能主动发送消息的特性,并未考虑到从机断电不能接收到Server消息的情况,Server会因为没有消息返回导致线程阻塞,不能继续轮询发送。
之后,对程序进行改进,用异步的方式解决了问题。
Server端代码Demo:
using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; public class NonBlockingServer { private const int bufferSize = 1024; private byte[] sendBuffer = Encoding.UTF8.GetBytes("Hello, client!"); // Data to send to clients private byte[] receiveBuffer = new byte[bufferSize]; // Data buffer to receive from clients private Socket serverSocket; private Timer timer; private int sendCounter = 0; private List<Socket> connectedClients = new List<Socket>(); // List to store connected client sockets public void StartServer() { // Create a TCP/IP socket. serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Bind the socket to the local endpoint and start listening for incoming connections. IPAddress ipAddress = IPAddress.Any; // Listen on all available interfaces int port = 12345; // Choose any available port IPEndPoint localEP = new IPEndPoint(ipAddress, port); serverSocket.Bind(localEP); serverSocket.Listen(10); Console.WriteLine("Server started. Waiting for clients..."); // Start the timer to periodically send data to connected clients. int intervalMilliseconds = 2000; // 2 seconds timer = new Timer(TimerCallback, null, 0, intervalMilliseconds); // Accept incoming connections asynchronously. serverSocket.BeginAccept(AcceptCallback, null); } private void AcceptCallback(IAsyncResult ar) { try { // Get the socket that represents the new connection. Socket clientSocket = serverSocket.EndAccept(ar); // Continue accepting new connections. serverSocket.BeginAccept(AcceptCallback, null); // Add the new client socket to the list of connected clients. connectedClients.Add(clientSocket); // Start receiving data from the client asynchronously. clientSocket.BeginReceive(receiveBuffer, 0, bufferSize, SocketFlags.None, ReceiveCallback, clientSocket); } catch (Exception ex) { Console.WriteLine($"Error accepting connection: {ex.Message}"); } } private void TimerCallback(object state) { try { // Send data to all connected clients asynchronously. foreach (var clientSocket in connectedClients) { clientSocket.BeginSend(sendBuffer, 0, sendBuffer.Length, SocketFlags.None, SendCallback, clientSocket); } // Increment the send counter for tracking purposes. sendCounter++; // On the 5th transmission, send a special message to the client. if (sendCounter == 5) { foreach (var clientSocket in connectedClients) { byte[] specialBuffer = Encoding.UTF8.GetBytes("Special message from server!"); clientSocket.BeginSend(specialBuffer, 0, specialBuffer.Length, SocketFlags.None, SendCallback, clientSocket); } sendCounter = 0; // Reset the counter for the next round. } } catch (Exception ex) { Console.WriteLine($"Error sending data: {ex.Message}"); } } private void ReceiveCallback(IAsyncResult ar) { try { // Get the socket that represents the client. Socket clientSocket = (Socket)ar.AsyncState; // End the receive operation and get the number of bytes received. int bytesRead = clientSocket.EndReceive(ar); if (bytesRead > 0) { // Process the received data (assuming it's text). string receivedData = Encoding.UTF8.GetString(receiveBuffer, 0, bytesRead); Console.WriteLine($"Received data from client: {receivedData}"); // Continue receiving more data. clientSocket.BeginReceive(receiveBuffer, 0, bufferSize, SocketFlags.None, ReceiveCallback, clientSocket); } else { // If no data is received, the client closed the connection. Console.WriteLine("Connection closed by the client."); connectedClients.Remove(clientSocket); clientSocket.Close(); } } catch (Exception ex) { Console.WriteLine($"Error receiving data: {ex.Message}"); } } private void SendCallback(IAsyncResult ar) { try { // End the send operation. Socket clientSocket = (Socket)ar.AsyncState; int bytesSent = clientSocket.EndSend(ar); Console.WriteLine($"Sent {bytesSent} bytes to a client."); } catch (Exception ex) { Console.WriteLine($"Error sending data: {ex.Message}"); } } public static void Main(string[] args) { NonBlockingServer server = new NonBlockingServer(); server.StartServer(); // Keep the console application running until the user decides to exit. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } }
Client端代码Demo:
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; public class NonBlockingClient { private const int bufferSize = 1024; private byte[] receiveBuffer = new byte[bufferSize]; // Data buffer to receive from the server private Socket clientSocket; public void StartClient() { // Create a TCP/IP socket. clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Set up the endpoint and connect to the server. IPAddress ipAddress = IPAddress.Parse("127.0.0.1"); // Replace with the server IP address. int port = 12345; // Replace with the server port number. IPEndPoint remoteEP = new IPEndPoint(ipAddress, port); try { clientSocket.Connect(remoteEP); Console.WriteLine("Connected to the server."); // Start receiving data from the server asynchronously. clientSocket.BeginReceive(receiveBuffer, 0, bufferSize, SocketFlags.None, ReceiveCallback, null); // Prevent the client from exiting immediately. // You can remove this line if you want the client to exit immediately after connecting. Thread.Sleep(Timeout.Infinite); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); clientSocket.Close(); } } private void ReceiveCallback(IAsyncResult ar) { try { // End the receive operation and get the number of bytes received. int bytesRead = clientSocket.EndReceive(ar); if (bytesRead > 0) { // Process the received data (assuming it's text). string receivedData = Encoding.UTF8.GetString(receiveBuffer, 0, bytesRead); Console.WriteLine($"Received data from server: {receivedData}"); // Continue receiving more data. clientSocket.BeginReceive(receiveBuffer, 0, bufferSize, SocketFlags.None, ReceiveCallback, null); } else { // If no data is received, the server closed the connection. Console.WriteLine("Connection closed by the server."); clientSocket.Close(); } } catch (Exception ex) { Console.WriteLine($"Error receiving data: {ex.Message}"); clientSocket.Close(); } } public static void Main(string[] args) { NonBlockingClient client = new NonBlockingClient(); client.StartClient(); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?