【问题标题】:C# Asynch Socket Server Example - How to Message all clients?C# 异步套接字服务器示例 - 如何向所有客户端发送消息?
【发布时间】:2011-04-28 19:16:09
【问题描述】:

大家好,你们太棒了,我得到了这么多问题的回答,这对我很有帮助。

我已经从 MSDN 修改了这个示例服务器异步套接字服务器: http://msdn.microsoft.com/en-us/library/fx6588te.aspx

我已经稍微修改了它,它可以满足我需要做的事情。问题是目前。那就是允许一次在一个客户端之间发送/接收。我需要能够查明连接到所述服务器的特定客户端,并向他们发送消息。

如何修改上面的示例,为每个连接添加一个标识符,或者至少包含一组标识符,以便我可以将消息发送给我需要的人。

客户端可能有大约 6-10 个自变量,每个变量都需要根据需要进行过滤(例如,向一组中的一组客户端发送数据)。我有一个效率不够高的旧阻塞服务器,我只是有一个完美地完成工作的二维数组。围绕过滤阵列的所有客户端的循环很好。但是在上面的例子中,连接似乎没有被识别或存储,你会推荐什么以及在哪里最容易存储它?

我对 .net 非常陌生,尤其是套接字服务器编程。任何帮助都会很棒!

编辑:我一直在努力解决这个问题,我听说虽然在“状态对象”中添加需要的变量,但问题是它会随着每个连接而更新。我需要知道谁已连接,以便我可以向已连接的客户端发送消息!

有什么想法吗?

【问题讨论】:

  • 我需要添加一个 hastable/arraylist 来存储连接的客户端吗?我可以简单地重复使用一个套接字连接,而不是像示例所示的那样重新创建新的连接吗?

标签: c# .net sockets msdn


【解决方案1】:

我们创建的其中一个工具也遇到了类似的情况(我没有直接使用它,但解决方案似乎运行良好)。每次我们收到客户时,我们都会将相关信息存储在一个类中(类似于示例中的 StateObject 类)并将该类添加到 ArrayList 中(效果很好),但我认为更好的解决方案是将类存储在 Dictionary :

http://msdn.microsoft.com/en-us/library/xfhwa508.aspx

Dictionary 类允许您将 Key 映射到对象。这使您可以使用唯一键轻松访问对象。因此,在接收到新客户端时,您可以按照您希望的方式为该客户端创建一个 ID(这可能只是一个整数,每次客户端连接时都会递增),创建一个状态对象类并将您需要的相关信息存储在该类中,然后将 Key Class 对添加到字典中,类似于:

// Global definition of Client dictionary
// The first argument within <> is the key type, the second argument
// is the type of object that key will map to
Dictionary<int, StateObject> Clients = new Dictionary<int, StateObject>();

// Accept client callback
public static void AcceptCallback(IAsyncResult ar)
{
    // Get the socket that handles the client request.
    Socket listener = (Socket) ar.AsyncState;
    Socket handler = listener.EndAccept(ar);

    StateObject client = new StateObject();

    // Then set all the variables of client here

    Clients.Add(ID, client);
}

注意:但是,您要创建自己的 ID,它们对于字典中的每个条目都必须是唯一的。

我的建议是将每个接受的套接字客户端的处理程序存储在 StateObject 中。这样,您始终可以访问可以向每个连接的客户端发送信息的句柄(这就是我们使用 Tcp 连接的方式,我们将 TcpClient 及其底层 Stream 存储在 StateObject 类中,然后通过这些与每个客户端进行通信变量。我假设这也可以通过 Sockets 实现?)

现在存储所有信息后,您可以使用字典中的 ID 键来识别要与哪些客户端进行通信。使用 LINQ 为您提供了一个不错的单行选择命令:

// Selects state objects from Clients dictionary where ID has a value greater than 5
IEnumerable<StateObject> Clients.Where(c => c.Key > 5).Select(c => c.Value);

(我认为这是有效的 LINQ 查询,但需要检查,它本质上是说从客户端列表中选择每个 StateObject,其中 ID 大于 5)

如果您不希望 ID 以这种方式识别客户端,您可以遍历字典中的每个 StateObject 并检查内部变量以查看您是否向客户端发送消息。比如:

foreach (StateObject client in Clients.Values)
{
    if (client.ImportantVariable == true)
        // Send client information via socket here
}

由您决定哪种方法最适合您的需求。希望这对您有所帮助,并且是一个可行的解决方案。

【讨论】:

  • 我已经能够修改我的代码以包含一个数组列表来密切关注客户端。我现在遇到的问题是,在测试我的客户端(向服务器发送命令)时,它们作为单独的客户端重新连接到我的服务器。我已将变量添加到我的 StateObject,然后在 AcceptCallBack 上将 StateObject 添加到数组列表中(因此我可以重新使用套接字发送数据)。当我从客户端重新发送数据时,我得到重复的对象,因为代码每次都只是启动一个新的 StateObject,我如何确保它在接收来自客户端的数据时识别现有对象?
  • @MWard 客户端是否在发送数据之前发送另一个连接请求,因为查看示例代码不应该发生您遇到的问题。你能把你正在处理的代码发给我吗?有机会我可以快速找你。
  • @TheRarebit 发送给您的最佳方式是什么?我有一个 Flash 电影,它在连接时会向服务器发送一串数据。如果我重新加载 flash 客户端,客户端将作为新用户加载,而不是断开连接。
  • @MWard 您可以将其发送到我个人资料中的电子邮件,或者最好将其上传到 mediafire 之类的文件共享站点并在此处共享链接,这意味着其他可能看到此内容的人可以访问它如果我无法为您找到解决方案:)
  • @TheRarebit - 我已将其添加到 pastebin 供您查看:pastebin.com/KUHHbaeR。作为一个提醒,我是一个初学者,只是想在我做任何优化之前得到一个可行的解决方案 lol
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-01
  • 2016-08-31
  • 1970-01-01
  • 2015-06-20
相关资源
最近更新 更多