我正在使用以下项目来创建server和client套接字之间的异步通信。当我运行这些项目时,我正在从客户端向服务器发送消息,因此我收到了消息:
数据:录制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实现中的主要代码,然后我调用我的对象。当我单击右键单击时,我更改了一个标志,捕获器停止。如何停止服务器或暂停以便通过左键单击再次打开它?
答案 0 :(得分:27)
首先回答问题:
问:是否有必要将所有内容转换为字符串?...一般来说,我是什么 想要是从一台计算机向另外两台计算机发送一个变量 在所有计算机上同时开始的过程。
答:不,发送时没有必要将所有内容转换为字符串 使用
问:我想要实现的是从服务器发送一个布尔变量 使用套接字的客户端Socket
。您可以发送您最想要的byte[]
。答:您的意思是
那样从发件人/收件人那里发送到boolean
还是byte
?因为你的基本变量类型 将来自Socket
byte
。您可以随时更改byte
通过像bool
bool val = byteToCheck > 0;
A2:由于您的服务器是
Console
应用程序,我建议您使用 查看十六进制string
到byte[]
转换。这样,你可以 在string
中写一些内容,但将其解释为byte[]
。校验 this。这里的整个想法非常简单。那就是:你输入string
,但会以byte[]
的形式发送。因为它是byte[]
你可以有任何价值。
在这里,我提出了解决方案来处理您的(1)多个客户端,(2)Async
connect&接受&接收,但有(3)发送同步,以及(4)从hex string
到byte[]
的转换(结构和想法),以及最后但并非最不重要的(5)工作代码与用户输入(供你更改此部分)进行测试!
我会使用简单的Socket
类来解决这个问题,因为这是我最熟悉的解决方案。但是如果你使用TcpListener.Server
(Socket
类的底层网络),你总是可以做同样的事情。而且,如你所愿,我会用ASync
来做到这一点。
您需要在服务器和客户端实现所需的几个步骤:
服务器强>
将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
}
由于服务器将为许多客户提供服务,因此我建议您使用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
,以便您可以收到下一条消息!< / 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());
}
}
并且假设您希望在收到消息后回复发件人,只需在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
}
在您的主要例程中添加更多内容后,您就完成了(!) - IF 您不要求以byte[]
现在,如果您想以<{1}}向所有您的客户发送内容,您只需要列出所有客户端(请参阅步骤4-5)。请参阅this并转换上面的byte[]
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
endConnectCallback
定义ASync
。但是,不像服务器需要重新调用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
的形式发送内容,因此您需要进行转换(请参阅服务器9中的说明)。然后你完全完成了!!
byte[]
<强>结果:强>
你走了!我通过发送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
属于Socket
类型。这可能会阻止客户端static
每次定义多次#34;定义&#34;,因为它与名为Socket
的{{1}}相同,它会引用同一个class
(尽管情况并非总是这样,至少根据OP的实验:他可以在同一台计算机上成功运行多个客户端)。
然而,要克服这一点并不难。只需将客户端应用程序移植到未启动为Program
类的平台(例如Socket
),所有上述代码仍将按正常方式运行。或者,如果必须使用static
运行,并且出现问题,只需复制客户端应用程序并使用不同的WinForms
或不同的Console Applications
名称重新定义它,以避免定义相同的{ {1}}由于相同的namespace
或class
。
但解决问题的最重要部分是明智地使用Socket
和namespace
来解决特定问题。
可以找到此主题的延续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);
}