c# - 使用套接字从服务器向客户端发送值

标签 c# sockets

我正在使用以下项目在 server 之间创建异步通信和 client socket 。当我运行这些项目时,我从客户端向服务器发送消息,因此我收到了消息:

Data : recording EOF, Sent 14 bytes to client.



我想要实现的是使用套接字从服务器向客户端发送一个 bool 变量。这样做是否可行,我想知道因为在代码中我有等待和监听的服务器以及发送数据的客户端,我可以做相反的事情吗?一般来说,我想要的是向几个客户端发送一个 bool 值。为什么我需要文件结尾才能发送字符串?是否有必要将所有内容都转换为字符串?

编辑 :一般来说,我想要的是将变量从一台计算机发送到另外两台计算机,以便在所有计算机中同时开始一个进程。事实上,创建一个切换器,发出信号以同时在 2-3 台机器上开始一个进程。

我尝试将以下代码用于 服务器 :
class Program
{
    const int PORT_NO = 2201;
    const string SERVER_IP = "127.0.0.1";
    static void Main(string[] args)
    {
        //---listen at the specified IP and port no.---
        IPAddress localAdd = IPAddress.Parse(SERVER_IP);
        TcpListener listener = new TcpListener(localAdd, PORT_NO);
        Console.WriteLine("Listening...");
        listener.Start();
        //---incoming client connected---
        TcpClient client = listener.AcceptTcpClient();
        //---get the incoming data through a network stream---
        NetworkStream nwStream = client.GetStream();
        byte[] buffer = new byte[client.ReceiveBufferSize];
        //---read incoming stream---
        int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
        //---convert the data received into a string---
        string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
        Console.WriteLine("Received : " + dataReceived);
        //---write back the text to the client---
        Console.WriteLine("Sending back : " + dataReceived);
        nwStream.Write(buffer, 0, bytesRead);
        client.Close();
        listener.Stop();
        Console.ReadLine();
    }
}

客户 :
class Program
{
    const int PORT_NO = 2201;
    const string SERVER_IP = "127.0.0.1";
    static void Main(string[] args)
    {
        //---data to send to the server---
        string textToSend = DateTime.Now.ToString();
        //---create a TCPClient object at the IP and port no.---
        TcpClient client = new TcpClient(SERVER_IP, PORT_NO);
        NetworkStream nwStream = client.GetStream();
        byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(textToSend);
        //---send the text---
        Console.WriteLine("Sending : " + textToSend);
        nwStream.Write(bytesToSend, 0, bytesToSend.Length);
        //---read back the text---
        byte[] bytesToRead = new byte[client.ReceiveBufferSize];
        int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
        Console.WriteLine("Received : " + Encoding.ASCII.GetString(bytesToRead, 0, bytesRead));
        Console.ReadLine();
        client.Close();
    }
}

以防万一我在同一台机器上工作。我总共将拥有 4 台机器,我希望其中一台机器向其余机器发出信号以开始录制 rgb 流。因此服务器应该向客户端发送信号以开始记录。我应该怎么做才能改变服务器发送数据而不是监听的行为。是否可以让多台机器监听并等待发出信号?

编辑:
private void mouseClick1(object sender, MouseEventArgs e)
    {

        Thread thread = new Thread(() => StartServer());
        thread.Start();

        if (e.Button == MouseButtons.Left)
        {
            button5.Enabled = false;
            button3.Enabled = true;

            try
            {
                obj = new Capturer();
            }
            catch (Exception e1)
            {
                Console.WriteLine("The process failed: {0}", e1.ToString());
            }
        }
    }

    private void mouseClick2(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Right)
        {
            obj.flag2 = true;
        }
    }

我的代码现在左键单击调用 startServer() 函数和一个新线程,这是@Ians 实现中的主要代码,然后我调用我的对象。当我单击右键单击时,我更改了一个标志并且捕获器停止了。如何停止服务器或暂停以通过左键单击再次打开它?

最佳答案

先回答问题:

Q: Is it necessary to convert everything to string?...In general what I want is to send a variable from one computer to two others in order a process to begin simultaneously in all computers.

A: No, it is not necessary to convert everything to string when sending using Socket. You may send byte[] which you most probably want.

Q: What I want to achieve is to send a boolean variable from the server to the client with the sockets

A: Do you mean boolean or byte? Because the basic variable type which you will get from the Socket is byte. You could always change byte to bool from the sender/receiver side by doing like

bool val = byteToCheck > 0;

A2: And since your server is Console Application, I recommend to take a look on hex string to byte[] conversion. This way, you could write something in string but interprets it as byte[]. Check this. The whole idea here is pretty simple. That is: you type in string, but it will be sent as byte[]. And since it is byte[] you can have any value in it.



在这里,我展示了我的解决方案来处理您的 (1) 多个客户,(2) Async连接 & 接受 & 接收,但具有 (3) 发送同步,以及 (4) 来自 hex string 的转换至 byte[] (结构和想法),最后但并非最不重要的(5)带有用户输入的工作代码(供您更改此部分)以进行测试!

我会用简单的 Socket 来解决这个问题class,因为它是我最熟悉的解决方案。但是如果你使用你的 TcpListener.Server,你总是可以做类似的事情。 (这是 Socket 类的底层网络)。而且,如您所愿,我会用 ASync 来做到这一点。 .

在服务器和客户端中实现您想要的目标需要几个步骤:

服务器
  • 让您的 Socket作为类字段而不是方法字段,因为您将在任何地方使用 if 并且您需要多种方法来实现您想要的。并在您开始主程序后立即对其进行初始化。
    const int PORT_NO = 2201;
    const string SERVER_IP = "127.0.0.1";
    static Socket serverSocket; //put here as static
    static void Main(string[] args) {
        //---listen at the specified IP and port no.---
        Console.WriteLine("Listening...");
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT_NO));
        serverSocket.Listen(4); //the maximum pending client, define as you wish
        //your next main routine
    }
    
  • 由于服务器会为很多客户端提供服务,我建议您使用 ASync而不是 Sync为过程。初始化您的 Socket通过使用 BeginAccept而不是使用 Accept , 放 acceptCallback在您的 BeginAccept
    static void Main(string[] args) {
        //---listen at the specified IP and port no.---
        Console.WriteLine("Listening...");
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT_NO));
        serverSocket.Listen(4); //the maximum pending client, define as you wish
        serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null);      
        //other stuffs
    }
    
  • 定义 acceptCallback ,这就是您接受 Socket 后会去的地方.把 EndAccept那里。
    private void acceptCallback(IAsyncResult result) { //if the buffer is old, then there might already be something there...
        System.Net.Sockets.Socket socket = null;
        try {
            socket = serverSocket.EndAccept(result); // To get your client socket
            //do something later
        } catch (Exception e) { // this exception will happen when "this" is be disposed...        
            //do something later
        }
    }
    
  • 我通常会列出我的客户端套接字,并在客户端处理上做一些事情(未列出) - 但这取决于需要。在这种情况下,您似乎需要它。并且不要忘记创建缓冲区等...这是用于缓冲传入的数据。
  • 开始接受从客户端收到的东西,使用另一个 ASync BeginReceive在客户端 Socket (现在你需要 receiveCallback )。然后,非常重要 ,重复您的 BeginAccept接受其他客户!
    private const int BUFFER_SIZE = 4096;
    private static byte[] buffer = new byte[BUFFER_SIZE]; //buffer size is limited to BUFFER_SIZE per message
    private static List<Socket> clientSockets = new List<Socket>(); //may be needed by you
    private static void acceptCallback(IAsyncResult result) { //if the buffer is old, then there might already be something there...
        Socket socket = null;
        try {
            socket = serverSocket.EndAccept(result); // The objectDisposedException will come here... thus, it is to be expected!
            //Do something as you see it needs on client acceptance such as listing
            clientSockets.Add(socket); //may be needed later
            socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket);
            serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null); //to receive another client
        } catch (Exception e) { // this exception will happen when "this" is be disposed...        
            //Do something here
            Console.WriteLine(e.ToString());
        }
    }
    
  • 定义您的 receiveCallback ,也就是说,当您从客户那里收到某些东西时。由于失败,这部分可能非常棘手!但基本上,您现在需要的只是 EndReceive再次,非常重要 , 重复 BeginReceive来自同一个客户端,这样您就可以收到下一条消息!
    const int MAX_RECEIVE_ATTEMPT = 10;
    static int receiveAttempt = 0; //this is not fool proof, obviously, since actually you must have multiple of this for multiple clients, but for the sake of simplicity I put this
    private static void receiveCallback(IAsyncResult result) {
        Socket socket = null;
        try {
            socket = (Socket)result.AsyncState; //this is to get the sender
            if (socket.Connected) { //simple checking
                int received = socket.EndReceive(result);
                if (received > 0) {
                    byte[] data = new byte[received]; //the data is in the byte[] format, not string!
                    Buffer.BlockCopy(buffer, 0, data, 0, data.Length); //There are several way to do this according to https://stackoverflow.com/questions/5099604/any-faster-way-of-copying-arrays-in-c in general, System.Buffer.memcpyimpl is the fastest
                    //DO SOMETHING ON THE DATA IN byte[] data!! Yihaa!!
                    Console.WriteLine(Encoding.UTF8.GetString(data)); //Here I just print it, but you need to do something else
                    receiveAttempt = 0; //reset receive attempt
                    socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); //repeat beginReceive
                } else if (receiveAttempt < MAX_RECEIVE_ATTEMPT) { //fail but not exceeding max attempt, repeats
                    ++receiveAttempt; //increase receive attempt;
                    socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); //repeat beginReceive
                } else { //completely fails!
                    Console.WriteLine("receiveCallback fails!"); //don't repeat beginReceive
                    receiveAttempt = 0; //reset this for the next connection
                }
            }
        } catch (Exception e) { // this exception will happen when "this" is be disposed...
            Console.WriteLine("receiveCallback fails with exception! " + e.ToString());
        }
    }
    
  • 假设您想在收到消息后回复您的发件人,只需在 if (received > 0) 中执行此操作即可。部分:
    if (received > 0) {
        byte[] data = new byte[received]; //the data is in the byte[] format, not string!
        //DO SOMETHING ON THE DATA int byte[]!! Yihaa!!
        Console.WriteLine(Encoding.UTF8.GetString(data)); //Here I just print it, but you need to do something else                     
    
        //Message retrieval part
        //Suppose you only want to declare that you receive data from a client to that client
        string msg = "I receive your message on: " + DateTime.Now;
        socket.Send(Encoding.ASCII.GetBytes(msg)); //Note that you actually send data in byte[]
        Console.WriteLine("I sent this message to the client: " + msg);
    
        receiveAttempt = 0; //reset receive attempt
        socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); //repeat beginReceive
    }
    
  • 在你的主要例程中多放一点东西后,你就完成了(!)- 如果 你不要求发送给客户 byte[]
  • 现在,如果您想向 发送信息全部 您的客户为 byte[]您只需要列出您的所有客户(请参阅步骤 4-5)。见 this并转换 result string以上(记得根据需要以十六进制 string 格式输入)到 byte[]然后使用您的客户端套接字列表将其发送给所有客户端(这里是需要它的地方!):
    static void Main(string[] args) {
        //---listen at the specified IP and port no.---
        Console.WriteLine("Listening...");
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT_NO));
        serverSocket.Listen(4); //the maximum pending client, define as you wish
        serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null);      
    
        //normally, there isn't anything else needed here
        string result = "";
        do {
            result = Console.ReadLine();
            if (result.ToLower().Trim() != "exit") {
                byte[] bytes = null;
                //you can use `result` and change it to `bytes` by any mechanism which you want
                //the mechanism which suits you is probably the hex string to byte[]
                //this is the reason why you may want to list the client sockets
                foreach(Socket socket in clientSockets)
                    socket.Send(bytes); //send everything to all clients as bytes
            }
        } while (result.ToLower().Trim() != "exit");
    }
    

  • 在这里,您或多或少地完成了您的服务器。接下来是你的客户

    客户:
  • 同样,把 Socket类上下文而不是方法上下文中的类,并在您启动程序后立即对其进行初始化
    const int PORT_NO = 2201;
    const string SERVER_IP = "127.0.0.1";
    static Socket clientSocket; //put here
    static void Main(string[] args) {
        //Similarly, start defining your client socket as soon as you start. 
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
        //your other main routines
    }
    
  • 然后通过ASync开始连接BeginConnect .我通常会通过 LoopConnect 走得更远只是为了像这样的失败处理。
    static void loopConnect(int noOfRetry, int attemptPeriodInSeconds) {
        int attempts = 0;
        while (!clientSocket.Connected && attempts < noOfRetry) {
            try {
                ++attempts;
                IAsyncResult result = clientSocket.BeginConnect(IPAddress.Parse(SERVER_IP), PORT_NO, endConnect, null);
                result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(attemptPeriodInSeconds));
                System.Threading.Thread.Sleep(attemptPeriodInSeconds * 1000);
            } catch (Exception e) {
                Console.WriteLine("Error: " + e.ToString());
            }
        }
        if (!clientSocket.Connected) {
            Console.WriteLine("Connection attempt is unsuccessful!");
            return;
        }
    }
    
  • 与您对服务器所做的类似的概念 BeginAccept您需要定义 endConnectCallbackASync BeginConnect你用。但在这里,不同于服务器 需要重新调用BeginAccept ,一旦连接,您无需再做任何新的BeginConnect因为您只需要连接 一次 .
  • 您可能要声明 buffer等然后,连接后,不要忘记下一个ASync BeginReceive处理消息检索部分(与服务器类似)
    private const int BUFFER_SIZE = 4096;
    private static byte[] buffer = new byte[BUFFER_SIZE]; //buffer size is limited to BUFFER_SIZE per message
    private static void endConnectCallback(IAsyncResult ar) {
        try {
            clientSocket.EndConnect(ar);
            if (clientSocket.Connected) {
                clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), clientSocket);
            } else {
                Console.WriteLine("End of connection attempt, fail to connect...");
            }
        } catch (Exception e) {
            Console.WriteLine("End-connection attempt is unsuccessful! " + e.ToString());
        }
    }
    
  • 当然,您需要定义您的 receiveCallback ,就像您为服务器所做的那样。是的,正如您所猜测的,它几乎与您为服务器所做的相同!
  • 您可以对数据做任何想做的事情。请注意,您收到的数据实际上在 byte[] 中,不是 string .所以你可以用它做任何事情。但是例如为了 , 我只会用 string显示。
    const int MAX_RECEIVE_ATTEMPT = 10;
    static int receiveAttempt = 0;
    private static void receiveCallback(IAsyncResult result) {
        System.Net.Sockets.Socket socket = null;
        try {
            socket = (System.Net.Sockets.Socket)result.AsyncState;
            if (socket.Connected) {
                int received = socket.EndReceive(result);
                if (received > 0) {
                    receiveAttempt = 0;
                    byte[] data = new byte[received];
                    Buffer.BlockCopy(buffer, 0, data, 0, data.Length); //copy the data from your buffer
                    //DO ANYTHING THAT YOU WANT WITH data, IT IS THE RECEIVED PACKET!
                    //Notice that your data is not string! It is actually byte[]
                    //For now I will just print it out
                    Console.WriteLine("Server: " + Encoding.UTF8.GetString(data));
                    socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket);
                } else if (receiveAttempt < MAX_RECEIVE_ATTEMPT) { //not exceeding the max attempt, try again
                    ++receiveAttempt;
                    socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket);
                } else { //completely fails!
                    Console.WriteLine("receiveCallback is failed!");
                    receiveAttempt = 0;
                    clientSocket.Close();
                }
            }
        } catch (Exception e) { // this exception will happen when "this" is be disposed...
            Console.WriteLine("receiveCallback is failed! " + e.ToString());
        }
    }
    
  • 最后... 是的,再次,正如您已经猜到的,您只需要在您的主要例程上做一些事情 - 假设您想用它来发送数据。因为你用的是Console但您希望它以 byte[] 的形式发送内容,您需要进行转换(请参阅服务器 9 中的说明。)。然后你就完全完成了!!
    static void Main(string[] args) {
        //Similarly, start defining your client socket as soon as you start. 
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        loopConnect(3, 3); //for failure handling
        string result = "";
        do {
            result = Console.ReadLine(); //you need to change this part
            if (result.ToLower().Trim() != "exit") {
                byte[] bytes = Encoding.ASCII.GetBytes(result); //Again, note that your data is actually of byte[], not string
                //do something on bytes by using the reference such that you can type in HEX STRING but sending thing in bytes
                clientSocket.Send(bytes);
            }
        } while (result.ToLower().Trim() != "exit");
    }
    


  • 结果:

    干得好!我通过发送 string 来测试它用于显示,但我已经提出了当您想将其更改为 byte[] 时所需的内容

    enter image description here

    enter image description here

    测试代码:

    服务器
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace TcpListenerConsoleApplication {
        class Program {
            const int PORT_NO = 2201;
            const string SERVER_IP = "127.0.0.1";
            static Socket serverSocket;
            static void Main(string[] args) {
                //---listen at the specified IP and port no.---
                Console.WriteLine("Listening...");
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT_NO));
                serverSocket.Listen(4); //the maximum pending client, define as you wish
                serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null);      
                string result = "";
                do {
                    result = Console.ReadLine();
                } while (result.ToLower().Trim() != "exit");
            }
    
            private const int BUFFER_SIZE = 4096;
            private static byte[] buffer = new byte[BUFFER_SIZE]; //buffer size is limited to BUFFER_SIZE per message
            private static void acceptCallback(IAsyncResult result) { //if the buffer is old, then there might already be something there...
                Socket socket = null;
                try {
                    socket = serverSocket.EndAccept(result); // The objectDisposedException will come here... thus, it is to be expected!
                    //Do something as you see it needs on client acceptance
                    socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket);
                    serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null); //to receive another client
                } catch (Exception e) { // this exception will happen when "this" is be disposed...        
                    //Do something here             
                    Console.WriteLine(e.ToString());
                }
            }
    
            const int MAX_RECEIVE_ATTEMPT = 10;
            static int receiveAttempt = 0; //this is not fool proof, obviously, since actually you must have multiple of this for multiple clients, but for the sake of simplicity I put this
            private static void receiveCallback(IAsyncResult result) {
                Socket socket = null;
                try {
                    socket = (Socket)result.AsyncState; //this is to get the sender
                    if (socket.Connected) { //simple checking
                        int received = socket.EndReceive(result);
                        if (received > 0) {
                            byte[] data = new byte[received]; //the data is in the byte[] format, not string!
                            Buffer.BlockCopy(buffer, 0, data, 0, data.Length); //There are several way to do this according to https://stackoverflow.com/questions/5099604/any-faster-way-of-copying-arrays-in-c in general, System.Buffer.memcpyimpl is the fastest
                            //DO SOMETHING ON THE DATA int byte[]!! Yihaa!!
                            Console.WriteLine(Encoding.UTF8.GetString(data)); //Here I just print it, but you need to do something else                     
    
                            //Message retrieval part
                            //Suppose you only want to declare that you receive data from a client to that client
                            string msg = "I receive your message on: " + DateTime.Now;                      
                            socket.Send(Encoding.ASCII.GetBytes(msg)); //Note that you actually send data in byte[]
                            Console.WriteLine("I sent this message to the client: " + msg);
    
                            receiveAttempt = 0; //reset receive attempt
                            socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); //repeat beginReceive
                        } else if (receiveAttempt < MAX_RECEIVE_ATTEMPT) { //fail but not exceeding max attempt, repeats
                            ++receiveAttempt; //increase receive attempt;
                            socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); //repeat beginReceive
                        } else { //completely fails!
                            Console.WriteLine("receiveCallback fails!"); //don't repeat beginReceive
                            receiveAttempt = 0; //reset this for the next connection
                        }
                    }
                } catch (Exception e) { // this exception will happen when "this" is be disposed...
                    Console.WriteLine("receiveCallback fails with exception! " + e.ToString());
                }
            }
    
        }
    }
    

    客户
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace TcpClientConsoleApplication {
        class Program {
            const int PORT_NO = 2201;
            const string SERVER_IP = "127.0.0.1";
            static Socket clientSocket; //put here
            static void Main(string[] args) {
                //Similarly, start defining your client socket as soon as you start. 
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                loopConnect(3, 3); //for failure handling
                string result = "";
                do {
                    result = Console.ReadLine(); //you need to change this part
                    if (result.ToLower().Trim() != "exit") {
                        byte[] bytes = Encoding.ASCII.GetBytes(result); //Again, note that your data is actually of byte[], not string
                        //do something on bytes by using the reference such that you can type in HEX STRING but sending thing in bytes
                        clientSocket.Send(bytes);
                    }
                } while (result.ToLower().Trim() != "exit");
            }
    
            static void loopConnect(int noOfRetry, int attemptPeriodInSeconds) {
                int attempts = 0;
                while (!clientSocket.Connected && attempts < noOfRetry) {
                    try {
                        ++attempts;
                        IAsyncResult result = clientSocket.BeginConnect(IPAddress.Parse(SERVER_IP), PORT_NO, endConnectCallback, null);
                        result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(attemptPeriodInSeconds));
                        System.Threading.Thread.Sleep(attemptPeriodInSeconds * 1000);
                    } catch (Exception e) {
                        Console.WriteLine("Error: " + e.ToString());
                    }
                }
                if (!clientSocket.Connected) {
                    Console.WriteLine("Connection attempt is unsuccessful!");
                    return;
                }
            }
    
            private const int BUFFER_SIZE = 4096;
            private static byte[] buffer = new byte[BUFFER_SIZE]; //buffer size is limited to BUFFER_SIZE per message
            private static void endConnectCallback(IAsyncResult ar) {
                try {
                    clientSocket.EndConnect(ar);
                    if (clientSocket.Connected) {
                        clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), clientSocket);
                    } else {
                        Console.WriteLine("End of connection attempt, fail to connect...");
                    }
                } catch (Exception e) {
                    Console.WriteLine("End-connection attempt is unsuccessful! " + e.ToString());
                }
            }
    
            const int MAX_RECEIVE_ATTEMPT = 10;
            static int receiveAttempt = 0;
            private static void receiveCallback(IAsyncResult result) {
                System.Net.Sockets.Socket socket = null;
                try {
                    socket = (System.Net.Sockets.Socket)result.AsyncState;
                    if (socket.Connected) {
                        int received = socket.EndReceive(result);
                        if (received > 0) {
                            receiveAttempt = 0;
                            byte[] data = new byte[received];
                            Buffer.BlockCopy(buffer, 0, data, 0, data.Length); //There are several way to do this according to https://stackoverflow.com/questions/5099604/any-faster-way-of-copying-arrays-in-c in general, System.Buffer.memcpyimpl is the fastest
                            //DO ANYTHING THAT YOU WANT WITH data, IT IS THE RECEIVED PACKET!
                            //Notice that your data is not string! It is actually byte[]
                            //For now I will just print it out
                            Console.WriteLine("Server: " + Encoding.UTF8.GetString(data));
                            socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket);
                        } else if (receiveAttempt < MAX_RECEIVE_ATTEMPT) { //not exceeding the max attempt, try again
                            ++receiveAttempt;
                            socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket);
                        } else { //completely fails!
                            Console.WriteLine("receiveCallback is failed!");
                            receiveAttempt = 0;
                            clientSocket.Close();
                        }
                    }
                } catch (Exception e) { // this exception will happen when "this" is be disposed...
                    Console.WriteLine("receiveCallback is failed! " + e.ToString());
                }
            }
        }
    }
    

    最后评论(编辑)

    由于上面的代码是使用 Console Application 运行的它必须与 static main void 一起运行关键词。因此客户Socket上面定义的是 static类型。这可能会阻止客户端 Socket每次“定义”时都会被多次定义,因为它是相同的 class命名 Program ,它将引用相同的 Socket (尽管情况可能并非总是如此,至少根据 OP 的实验:他可以在同一台计算机上成功运行多个客户端)。

    尽管如此,克服这一点并不难。只需将客户端应用程序移植到非启动的平台 static类(例如 WinForms )和所有上述代码仍将正常运行。或者,如果它必须使用 Console Applications 运行,出现问题,只需复制客户端应用程序并使用不同的namespace重新定义它或不同 class避免定义相同的名称 Socket由于相同 namespaceclass .

    但解决这个问题最重要的部分是使用 AsyncSync明智地解决给定的问题。

    继续这个话题可以找到here

    关于c# - 使用套接字从服务器向客户端发送值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34586733/

    相关文章:

    javascript - 获取服务器上选项卡的套接字实例

    c# - 在 DocumentReady 事件中文档没有准备好?

    c# - 从 C# 解决方案调试 C++ 解决方案

    c# - 可以混合对象初始值设定项和集合初始值设定项吗?

    c# - 使用 DataAnnotations 和 DataType 进行电子邮件模型验证

    php - 使用 RabbitMQ 的 Swoole

    c++ - 谈论套接字时的同步和异步术语

    c - 使用 fork、execvp 传输两个命令,然后将输出重定向到套接字

    multithreading - 使用 libev 的多线程套接字服务器

    c# - 从另一个列表创建一个列表,按某些索引过滤