了解委托流程
Understanding Delegate flow
首先,如果这看起来我不应该 post 这个问题,我想道歉。自过去 2 周以来,我一直在努力理解这段代码,但都无济于事。
我的主要问题是理解这个代表在这里是如何工作的
messageInformer = new MessageInformer(this.Broadcast);
我无法使用调试器来跟踪代码,因为 VS 不允许我这样做。我了解 Socket 连接、发送和接收,但我不明白这里的委托是如何工作的。据我观察,将多个客户端连接到服务器后,当客户端向服务器发送消息时,其他客户端会收到与服务器相同的消息
我了解委托作为函数指针,我知道委托的基础知识。
谁能给我解释一下这个委托的使用流程?
查找以下所有代码:
Server.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace SimpleChatServer.Communication
{
class Server
{
private Socket serverSock;
private List<ClientHandler> clientsConnected = new List<ClientHandler>();
private MessageInformer messageInformer;
public Server()
{
serverSock = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
Console.WriteLine("Socket created");
serverSock.Bind(
new IPEndPoint(IPAddress.Loopback, 8055));
Console.WriteLine("Binding done");
serverSock.Listen(5);
Console.WriteLine("Listening started");
messageInformer = new MessageInformer(this.Broadcast);
}
public void StartAccepting()
{
while (true)
{
clientsConnected.Add(new ClientHandler(serverSock.Accept(), messageInformer));
Thread thread = new Thread(new ParameterizedThreadStart(clientsConnected.Last().StartReceiving));
thread.Start();
Console.WriteLine("New Client accepted");
}
}
private void Broadcast(Socket caller, string message)
{
foreach (var item in clientsConnected)
{
if(!item.ClientSock.Equals(caller))
item.ClientSock.Send(Encoding.UTF8.GetBytes(message));
}
}
}
}
ClientHandler.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
namespace SimpleChatServer.Communication
{
class ClientHandler
{
private Socket clientSock;
private MessageInformer informer;
public Socket ClientSock
{
get { return clientSock; }
//set { clientSock = value; }
}
private byte[] buffer = new byte[512];
public ClientHandler(Socket clientSock, MessageInformer informer)
{
this.clientSock = clientSock;
this.informer = informer;
}
/// <summary>
/// Receive messages from the client
/// </summary>
/// <param name="obj"></param>
public void StartReceiving(object obj)
{
int length;
string name = "";
string message = "";
#region Handle Name
do
{
length = clientSock.Receive(buffer);
name += Encoding.UTF8.GetString(buffer, 0, length);
} while (!name.Contains("\r\n"));
name = name.Substring(0, name.Length - 2);
clientSock.Send(Encoding.UTF8.GetBytes("hello " + name + "\r\n"));
#endregion
while (true)
{
length = clientSock.Receive(buffer);
message += Encoding.UTF8.GetString(buffer, 0, length);
if (message.Contains("\r\n"))
{
Console.Write(name + ": " + message);
informer(clientSock, name + ": " + message);
message = "";
}
}
}
}
}
Delegaters.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
namespace SimpleChatServer.Communication
{
public delegate void MessageInformer(Socket caller, string message);
}
program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SimpleChatServer.Communication;
namespace SimpleChatServer
{
class Program
{
static void Main(string[] args)
{
Server server = new Server();
server.StartAccepting();
server.StartAccepting();
Console.ReadLine();
}
}
}
让我们从上到下开始:
public delegate void MessageInformer(Socket caller, string message);
这是委托定义,这里还没有完成任何工作。
messageInformer = new MessageInformer(this.Broadcast);
这会将私有变量 messageInformer(属于 MessageInformer 委托类型)设置为新值:针对此 class 方法广播的实例化委托。它必须具有与委托类型相同的参数才能用作此委托的目标。比较这些参数:
public delegate **void** MessageInformer(**Socket** caller, **string** message);
private **void** Broadcast(**Socket** caller, **string** message)
调用 messageInformer(mySocket, myMessage);
现在会将调用重定向到 Server.Broadcast(mySocket, MyMessage)
,无论从何处调用此委托,因为此委托已绑定到服务器广播方法的此实例,并且不依赖于中的上下文它被称为。
clientsConnected.Add(new ClientHandler(serverSock.Accept(), messageInformer));
此行使用新连接的套接字创建了一个新的 ClientHandler,并为其提供了仍然指向 Server.Broadcast 的 messageInformerDelegate,即使它现在已提供给 ClientHandler。然后委托在 ClientHandler.
中保存为 informer
informer(clientSock, name + ": " + message);
ClientHandler.StartReceiving 方法中的这一行现在调用 Server.BroadCast 方法,提供它自己的套接字和它收到的消息。如果您在 ClientHandler 中拥有对服务器的引用,则可以更改为 myServer.Broadcast(clientSock, name + ": "+ message);
。
然后 Server.Broadcast 方法循环遍历所有套接字,并转发收到的消息,然后检查委托调用提供的套接字(在这种情况下始终是调用 Clienthandler 的套接字)是否是套接字此消息转发给。
首先,如果这看起来我不应该 post 这个问题,我想道歉。自过去 2 周以来,我一直在努力理解这段代码,但都无济于事。
我的主要问题是理解这个代表在这里是如何工作的
messageInformer = new MessageInformer(this.Broadcast);
我无法使用调试器来跟踪代码,因为 VS 不允许我这样做。我了解 Socket 连接、发送和接收,但我不明白这里的委托是如何工作的。据我观察,将多个客户端连接到服务器后,当客户端向服务器发送消息时,其他客户端会收到与服务器相同的消息
我了解委托作为函数指针,我知道委托的基础知识。
谁能给我解释一下这个委托的使用流程?
查找以下所有代码:
Server.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace SimpleChatServer.Communication
{
class Server
{
private Socket serverSock;
private List<ClientHandler> clientsConnected = new List<ClientHandler>();
private MessageInformer messageInformer;
public Server()
{
serverSock = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
Console.WriteLine("Socket created");
serverSock.Bind(
new IPEndPoint(IPAddress.Loopback, 8055));
Console.WriteLine("Binding done");
serverSock.Listen(5);
Console.WriteLine("Listening started");
messageInformer = new MessageInformer(this.Broadcast);
}
public void StartAccepting()
{
while (true)
{
clientsConnected.Add(new ClientHandler(serverSock.Accept(), messageInformer));
Thread thread = new Thread(new ParameterizedThreadStart(clientsConnected.Last().StartReceiving));
thread.Start();
Console.WriteLine("New Client accepted");
}
}
private void Broadcast(Socket caller, string message)
{
foreach (var item in clientsConnected)
{
if(!item.ClientSock.Equals(caller))
item.ClientSock.Send(Encoding.UTF8.GetBytes(message));
}
}
}
}
ClientHandler.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
namespace SimpleChatServer.Communication
{
class ClientHandler
{
private Socket clientSock;
private MessageInformer informer;
public Socket ClientSock
{
get { return clientSock; }
//set { clientSock = value; }
}
private byte[] buffer = new byte[512];
public ClientHandler(Socket clientSock, MessageInformer informer)
{
this.clientSock = clientSock;
this.informer = informer;
}
/// <summary>
/// Receive messages from the client
/// </summary>
/// <param name="obj"></param>
public void StartReceiving(object obj)
{
int length;
string name = "";
string message = "";
#region Handle Name
do
{
length = clientSock.Receive(buffer);
name += Encoding.UTF8.GetString(buffer, 0, length);
} while (!name.Contains("\r\n"));
name = name.Substring(0, name.Length - 2);
clientSock.Send(Encoding.UTF8.GetBytes("hello " + name + "\r\n"));
#endregion
while (true)
{
length = clientSock.Receive(buffer);
message += Encoding.UTF8.GetString(buffer, 0, length);
if (message.Contains("\r\n"))
{
Console.Write(name + ": " + message);
informer(clientSock, name + ": " + message);
message = "";
}
}
}
}
}
Delegaters.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
namespace SimpleChatServer.Communication
{
public delegate void MessageInformer(Socket caller, string message);
}
program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SimpleChatServer.Communication;
namespace SimpleChatServer
{
class Program
{
static void Main(string[] args)
{
Server server = new Server();
server.StartAccepting();
server.StartAccepting();
Console.ReadLine();
}
}
}
让我们从上到下开始:
public delegate void MessageInformer(Socket caller, string message);
这是委托定义,这里还没有完成任何工作。
messageInformer = new MessageInformer(this.Broadcast);
这会将私有变量 messageInformer(属于 MessageInformer 委托类型)设置为新值:针对此 class 方法广播的实例化委托。它必须具有与委托类型相同的参数才能用作此委托的目标。比较这些参数:
public delegate **void** MessageInformer(**Socket** caller, **string** message);
private **void** Broadcast(**Socket** caller, **string** message)
调用 messageInformer(mySocket, myMessage);
现在会将调用重定向到 Server.Broadcast(mySocket, MyMessage)
,无论从何处调用此委托,因为此委托已绑定到服务器广播方法的此实例,并且不依赖于中的上下文它被称为。
clientsConnected.Add(new ClientHandler(serverSock.Accept(), messageInformer));
此行使用新连接的套接字创建了一个新的 ClientHandler,并为其提供了仍然指向 Server.Broadcast 的 messageInformerDelegate,即使它现在已提供给 ClientHandler。然后委托在 ClientHandler.
中保存为informer
informer(clientSock, name + ": " + message);
ClientHandler.StartReceiving 方法中的这一行现在调用 Server.BroadCast 方法,提供它自己的套接字和它收到的消息。如果您在 ClientHandler 中拥有对服务器的引用,则可以更改为 myServer.Broadcast(clientSock, name + ": "+ message);
。
然后 Server.Broadcast 方法循环遍历所有套接字,并转发收到的消息,然后检查委托调用提供的套接字(在这种情况下始终是调用 Clienthandler 的套接字)是否是套接字此消息转发给。