首页 > 编程语言 >C#中Socket编程,异步实现Server端定时发送消息

C#中Socket编程,异步实现Server端定时发送消息

时间:2023-07-31 22:14:10浏览次数:48  
标签:Console Socket C# private Server client WriteLine data clientSocket

在最近项目需求中,要求服务端定时向客服端发送消息。由于客户端从机的特性,只能接收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();
    }
}

标签:Console,Socket,C#,private,Server,client,WriteLine,data,clientSocket
From: https://www.cnblogs.com/trendyshuai/p/17594683.html

相关文章

  • JavaScript
    1、什么是JavaScriptJavaScript是一门世界上最流行的脚本语言一个合格的后端人员,必须精通JavaScript历史:https://blog.csdn.net/kese7952/article/details/793578682、快速入门2.1、引入JavaScript1、内部标签<script>//......</script>2、外部标签abs.js//......
  • HBase-compact的作用、两种实现方式及区别
    在hbase中每当有memstore数据flush到磁盘之后,就形成一个storefile,当storeFile的数量达到一定程度后,就需要将storefile文件来进行compaction操作。Compact的作用:①合并文件②清除过期,多余版本的数据③提高读写数据的效率HBase中实现了两种compaction的方式:minorandmaj......
  • *CTF和nssctf#16的wp
    *ctf2023fcalc分析程序本题存在漏洞,是生活中很容易犯的错误,就是循环或者判断的时候没有注意多一还是少一,这种会发生很严重的问题。比如这个题在过滤数字的时候没有过滤掉0,所以输入0的时候会跳转到栈的内容,从而被攻击者执行shellcode。不过本题目不能直接执行,因为存在一个对浮......
  • 字符编码笔记:ASCII,Unicode和UT…
    字符编码笔记:ASCII,Unicode和UTF-8作者:阮一峰今天中午,我突然想搞清楚Unicode和UTF-8之间的关系,于是就开始在网上查资料。结果,这个问题比我想象的复杂,从午饭后一直看到晚上9点,才算初步搞清楚。下面就是我的笔记,主要用来整理自己的思路。但是,我尽量试图写得通俗易懂,希望能对......
  • PCB layout,或称为PCB设计,是将电子元件和连接线路等布局到电路板上的过程。
    1.设计思路在进行PCBlayout前,需要明确电路板的设计目标、功能、性能指标等,按照最终需求来设计电路板的参数、尺寸和针脚安排等。2.元器件部署按照较理想的排列方式,分配和放置电子元件的位置和布局,也就是确定元器件的摆放位置、取向和连线顺序,配合特定的机械框架基本......
  • leetcode-n-sum总结
    总结一下leetcode中遇见的2-sum,3-sum,4-sum问题,并扩展到n-sum。1.两数之和-力扣(LeetCode)梦开始的地方,不多说。classSolution{publicint[]twoSum(int[]nums,inttarget){Map<Integer,Integer>map=newHashMap<>();for(inti=0;i<......
  • pytorch-tensor属性统计(norm,max,min...)
    statistics▪norm(范数)▪mean,sum(平均值,求和)▪prod(累乘)▪max,min,argmin,argmax▪kthvalue,topk(第k大)norm(范式)这里面有一范式和二范式。一范式:\[||x||_1=\sum_k|x_k|\]二范式:\[||x||_1=\sqrt{\sum_k{x_k^2}}\]a.norm(k,dim)这个dim,可以不填,不填就是......
  • 【补充】isinstance()issubclass()
    【补充】isinstance()/issubclass()isinstance()函数和issubclass()函数是Python中的两个内置函数用于判断对象与类之间的关系。【1】isinstance()isinstance()函数用于检查一个对象是否是一个类的实例。它接受两个参数第一个参数是待检查的对象第二个参数是类或类型。......
  • 【补充】docker-compose部署Yapi
    【补充】docker-compose部署Yapi参考博客:docker-compose部署Yapi-知乎(zhihu.com)【1】了解DockerCompose:DockerCompose是Docker官方推出的一个用于定义和运行多个Docker容器的工具。通过使用DockerCompose,你可以使用一个单独的yaml文件来定义多个相关的服务,然后使......
  • 【补充】什么是mock数据
    【补充】什么是mock数据【1】介绍Mock数据是在软件开发过程中使用的一种方式,它用于模拟真实数据源的数据,并且具有相似的数据结构和字段。Mock数据通常被用作在实际的数据源不可用或者无法获得时进行开发、测试和演示。Mock数据的主要目的是在软件开发的早期阶段就提供可......