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

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

数据:记录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实现中的主要代码,然后我调用我的对象。 当我单击右键单击时,我更改了一个标志,捕获器停止。 如何通过左键单击停止服务器或暂停以再次打开它?

首先回答问题:

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

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

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

答:你的意思是boolean还是byte ? 因为从Socket获得的基本变量类型是byte 。 你总是可以通过这样做从发送者/接收者端将byte更改为bool

bool val = byteToCheck > 0;

A2:由于您的服务器是Console应用程序,我建议您查看hexstringbyte[]转换。 这样,你可以用string写一些东西,但把它解释为byte[] 。 检查一下 。 这里的整个想法非常简单。 那就是:你键入string ,但它将作为byte[]发送。 因为它是byte[]你可以拥有任何值。

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

我会使用简单的Socket类解决这个问题,因为它是我最熟悉的解决方案。 但是如果使用TcpListener.Server (它是Socket类的底层网络),你总是可以做类似的TcpListener.Server 。 而且,如你所愿,我会用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进行处理。 使用BeginAccept而不是使用Accept初始化Socket ,将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时的acceptCallback 。 把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. 开始接受从客户端接收的内容,在客户端Socket上使用另一个BeginReceive (现在需要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 clientSockets = new List(); //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 ,这样你就可以收到它的下一条消息了!

     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. 在你的主程序中添加了一些东西后,你就完成了(!) - 如果你没有要求以byte[]发送给客户端

  9. 现在,如果您想以byte[]所有客户发送内容,则只需列出所有客户端(请参阅步骤4-5)。 看到这个并将上面的result string (请记住按需要以hexstring格式键入)转换为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"); } 

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


客户:

  1. 类似地,将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 } 
  2. 然后开始通过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; } } 
  3. 与您对服务器的操作类似的概念BeginAccept您需要为您使用的BeginConnect定义endConnectCallback 。 但在这里, 需要重新调用BeginAccept 服务器不同 ,一旦连接,您不需要执行任何新的BeginConnect因为您只需要连接一次

  4. 您可能想要声明buffer等。然后,在连接之后,不要忘记下一个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()); } } 
  5. 当然,您需要定义您的receiveCallback ,就像您为服务器所做的那样。 是的,正如您所猜测的那样,它几乎与您为服务器所做的完全相同!

  6. 您可以使用数据执行任何操作。 请注意,您收到的数据实际上是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()); } } 
  7. 在最后......是的,再次,正如你已经猜到的,你只需要在主程序上做一些事情 - 假设你想用它来发送数据。 因为您使用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[]时我已经把它放了

在此处输入图像描述

在此处输入图像描述


测试代码:

服务器

 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关键字运行。 因此,上面定义的客户端Socketstatic类型的。 这可能会阻止客户端Socket在每次“定义”时多次定义,因为它与名为Program class相同,它将引用相同的Socket (尽管可能并非总是如此,至少根据OP的实验:他可以在同一台计算机上成功运行多个客户端)。

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

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


可在此处找到此主题的延续

为什么不让您的生活更轻松并使用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("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("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(); } } } 

为了使上述function正常工作,您需要以下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

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

在页面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); }