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

时间:2016-01-04 07:48:12

标签: c# sockets

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

  

数据:录制EOF,向客户端发送14个字节。

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

编辑:一般来说,我想要的是将变量从一台计算机发送到另外两台计算机,以便在所有计算机中同时开始一个过程。事实上,要创建一个切换器,它可以同时在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实现中的主要代码,然后我调用我的对象。当我单击右键单击时,我更改了一个标志,捕获器停止。如何停止服务器或暂停以便通过左键单击再次打开它?

4 个答案:

答案 0 :(得分:27)

首先回答问题:

  

问:是否有必要将所有内容转换为字符串?...一般来说,我是什么   想要是从一台计算机向另外两台计算机发送一个变量   在所有计算机上同时开始的过程。

     

答:不,发送时没有必要将所有内容转换为字符串   使用Socket。您可以发送您最想要的byte[]

     问:我想要实现的是从服务器发送一个布尔变量   使用套接字

的客户端      

答:您的意思是boolean还是byte?因为你的基本变量类型   将来自Socket byte。您可以随时更改byte   通过像

那样从发件人/收件人那里发送到bool      

bool val = byteToCheck > 0;

     

A2:由于您的服务器是Console应用程序,我建议您使用   查看十六进制stringbyte[]转换。这样,你可以   在string中写一些内容,但将其解释为byte[]。校验   this。这里的整个想法非常简单。那就是:你输入   string,但会以byte[]的形式发送。因为它是byte[]   你可以有任何价值。

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

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

您需要在服务器和客户端实现所需的几个步骤:

服务器

  1. Socket作为类字段而不是方法字段,因为您将在任何地方使用,并且您需要多种方法来实现您想要的效果。并在您开始主要程序后立即初始化它。

    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
    }
    
  2. 由于服务器将为许多客户提供服务,因此我建议您使用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
    }
    
  3. 定义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
        }
    }
    
  4. 我通常会列出我的客户端套接字,并在客户端处理上做一些事情(不公开) - 但这取决于需要。在这种情况下,您似乎需要它。并且不要忘记创建缓冲区等...这是用于缓冲传入的数据。

  5. 开始接受客户端收到的内容,使用客户端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());
        }
    }
    
  6. 定义您的receiveCallback,即从您的客户收到邮件时。由于失败,这部分可能非常棘手!但基本上,您现在需要的只是EndReceive而且非常重要,从同一客户端重复BeginReceive,以便您可以收到下一条消息!< / p>

    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());
        }
    }
    
  7. 并且假设您希望在收到消息后回复发件人,只需在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
    }
    
  8. 在您的主要例程中添加更多内容后,您就完成了(!) - IF 您不要求以byte[]

  9. 现在,如果您想以<{1}}向所有您的客户发送内容,您只需要列出所有客户端(请参阅步骤4-5)。请参阅this并转换上面的byte[] result(请记住根据需要以十六进制string格式输入)string然后将其发送给所有使用的客户端您的客户端套接字列表(这是需要的地方!):

    byte[]
  10. 在这里,您或多或少地完成了您的服务器。接下来是您的客户

    <强>客户端:

    1. 同样,将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
    2. 然后开始按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
    3. 与您对服务器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 endConnectCallback定义ASync。但是,不像服务器需要重新调用BeginConnect,一旦连接,您就不需要执行任何新的BeginAccept,因为您只需要连接<强>一旦

    4. 您可能需要声明BeginConnect等。然后,在您连接后,请不要忘记下一个buffer ASync来处理邮件检索部分(类似与服务器)

      BeginReceive
    5. 当然,您需要定义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()); } } ,就像您为服务器所做的那样。是的,正如您所猜测的那样,它几乎与您为服务器所做的完全相同!

    6. 您可以使用数据执行任何操作。请注意,您收到的数据实际上位于receiveCallback,而不是byte[]。所以你可以用它做任何事情。但例如,我只会使用string来显示。

      string
    7. 就在最后......是的,再次,正如你已经猜到的那样,你只需要在你的主程序上做一些事情 - 假设你想用它来发送数据。由于您使用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的形式发送内容,因此您需要进行转换(请参阅服务器9中的说明)。然后你完全完成了!!

      byte[]
    8. <强>结果:

      你走了!我通过发送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

      时,我已经提出了所需的内容

      enter image description here

      enter image description here

      测试代码:

      服务器

      byte[]

      <强>客户端

      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每次定义多次#34;定义&#34;,因为它与名为Socket的{​​{1}}相同,它会引用同一个class(尽管情况并非总是这样,至少根据OP的实验:他可以在同一台计算机上成功运行多个客户端)。

      然而,要克服这一点并不难。只需将客户端应用程序移植到未启动为Program类的平台(例如Socket),所有上述代码仍将按正常方式运行。或者,如果必须使用static运行,并且出现问题,只需复制客户端应用程序并使用不同的WinForms或不同的Console Applications名称重新定义它,以避免定义相同的{ {1}}由于相同的namespaceclass

      但解决问题的最重要部分是明智地使用Socketnamespace来解决特定问题。

      可以找到此主题的延续here

答案 1 :(得分:5)

为什么不让您的生活更轻松并使用SignalR? 下面您可以看到服务器和客户端是控制台应用程序的简单示例

客户端(多次运行此.exe)

using System;
using Microsoft.AspNet.SignalR.Client;

namespace SignalRClient
{
    class Program
    {
        private static IHubProxy HubProxy { get; set; }
        const string ServerURI = "http://localhost:1234/signalr";
        private static HubConnection Connection { get; set; }

        static void Main(string[] args)
        {
            Connection = new HubConnection(ServerURI);
            HubProxy = Connection.CreateHubProxy("MyHub");

            HubProxy.On<string, string>("SendMessage", (name, message) => Console.WriteLine(name + ":" + message));
            Connection.Start().Wait();

            Console.WriteLine("Press Enter to stop client");
            Console.ReadLine();
        }
    }
}

服务器(在运行客户端之前运行此.exe)

using System;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Client;
using Microsoft.Owin.Hosting;
using Owin;

namespace SignalRServer
{
    class Program
    {
        static private IDisposable SignalR { get; set; }
        const string ServerURI = "http://localhost:1234";
        private static IHubProxy HubProxy { get; set; }
        private static HubConnection Connection { get; set; }
        static void Main(string[] args)
        {
            SignalR = WebApp.Start(ServerURI);
            Console.WriteLine("Server running at " + ServerURI);

            Connection = new HubConnection(ServerURI);
            HubProxy = Connection.CreateHubProxy("MyHub");
            HubProxy.On<string, string>("SendMessage", (name, message) => Console.WriteLine(name + ":" + message));
            Connection.Start().Wait();

            string messageToSentToClients;
            do
            {
                Console.WriteLine("Type someting to send to clients and press enter");
                messageToSentToClients = Console.ReadLine();
               HubProxy.Invoke("Send", "Server", messageToSentToClients);
           } while (messageToSentToClients != "exit");

       }
    }

    public class MyHub : Hub
    {
        public void Send(string name, string message) { Clients.All.sendMessage(name, message); }
    }

    class Startup
    {
        public void Configuration(IAppBuilder app) { app.MapSignalR(); }
    }
}

为了使上述功能正常工作,您需要以下NuGet包:

<强>客户端:
          Microsoft.AspNet.SignalR.Client
服务器
          Microsoft.AspNet.SignalR
          Microsoft.AspNet.SignalR.Client
          Microsoft.AspNet.SignalR.SelfHost
          Microsoft.Owin.Host.HttpListener

如果您希望服务器/客户端位于不同的计算机上,您只需更改两个项目中的ServeURI属性:

//Clients
const string ServerURI = "http://SERVER_IP:PORT/signalr";
//Server
const string ServerURI = "http://SERVER_IP:PORT"; 

你可以在WinForms中找到另一个类似的例子:
https://code.msdn.microsoft.com/windowsdesktop/Using-SignalR-in-WinForms-f1ec847b

答案 2 :(得分:2)

您可以将数据发送到客户端,并且可以通过类似于客户端的方式实现 - &gt;服务器(除非您的套接字仅接收,如果是,则将它们切换为发送和接收)。发送布尔值需要转换为字节,您可以通过BitConverter类实现此目的。

答案 3 :(得分:2)

在页面https://msdn.microsoft.com/en-us/library/fx6588te%28v=vs.110%29.aspx上查看方法AcceptCallback(客户端连接时调用它)。有一行Socket handler = listener.EndAccept(ar);。 每个客户端连接时都会发生这种情况,因此请将这些Socket实例保留到某个列表中。 当您想要向客户端发送数据时,请使用同一示例中的Send方法与列表中的每个套接字(或者如果您只想发送给某些客户端,则选择性地)。

private static void Send(Socket handler, String data) {
    // Convert the string data to byte data using ASCII encoding.
    byte[] byteData = Encoding.ASCII.GetBytes(data);

    // Begin sending the data to the remote device.
    handler.BeginSend(byteData, 0, byteData.Length, 0,
        new AsyncCallback(SendCallback), handler);
}