Пример C # Asynch Socket Server - Как отправить сообщение всем клиентам? - PullRequest
0 голосов
/ 28 апреля 2011

Привет всем, вы, ребята, здесь потрясающие, я отвечаю на очень много вопросов, это очень помогает.

Я изменил этот пример сервера Asynchronous Socket Server из MSDN: http://msdn.microsoft.com/en-us/library/fx6588te.aspx

Я немного изменил его, и он работает с тем, что мне нужно сделать. вопрос на данный момент. То есть позволяет отправлять / получать между одним клиентом одновременно. Мне нужно иметь возможность точно определить конкретных клиентов, которые подключены к указанному серверу, и отправить им сообщение.

Как я могу изменить приведенный выше пример, включив в него идентификатор для каждого соединения или хотя бы набор идентификаторов, чтобы я мог отправлять сообщения тем, кому мне нужно.

У клиентов может быть около 6-10 независимых переменных, каждая из которых должна фильтроваться по мере необходимости (например, отправка данных группе клиентов в группе). У меня был старый блокирующий сервер, который не был достаточно эффективным, у меня просто был двухмерный массив, который отлично справлялся с работой. Цикл вокруг всех клиентов, фильтрующих массив, был в порядке. Но в приведенном выше примере, кажется, соединения не идентифицированы и не сохранены, что бы вы порекомендовали и где было бы проще всего их хранить?

Я довольно новичок в .net и особенно в программировании на сокет-серверах. Любая помощь будет отличной!

edit: Я бился головой об кирпичную стену об этом, хотя я слышал, что при добавлении нужных переменных в «объекте состояния» проблема заключается в том, что он обновляется с каждым соединением. Мне нужно знать, кто подключен, чтобы я мог отправлять сообщения подключенным клиентам!

Есть идеи?

1 Ответ

0 голосов
/ 04 мая 2011

У нас была похожая ситуация с одним из созданных нами инструментов (я не работал над ним напрямую, но решение, кажется, работает нормально).Каждый раз, когда мы получали клиента, мы сохраняли соответствующую информацию в классе (аналогичном классу StateObject в примере) и добавляли этот класс в ArrayList (который работает нормально), но я полагаю, что более удачным решением было бы хранить классы в словаре.:

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

Класс Dictionary позволяет сопоставить ключ с объектом.Это позволяет легко получать доступ к объектам с помощью уникального ключа.Таким образом, при получении нового клиента вы можете создать идентификатор для этого клиента любым удобным для вас способом (это может быть просто целое число, которое увеличивается при каждом подключении клиента), создать класс объекта состояния и сохранить необходимую информацию в этом классе.затем добавьте пару слов «Класс ключей» в словарь, так что-то похожее на:

// 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);
}

Примечание. Однако, если вы хотите создать свои идентификаторы, они должны быть уникальными для каждой записи в Словаре.

Мой совет - хранить обработчик для каждого принятого клиента сокета в StateObject.Таким образом, у вас всегда есть доступ к дескриптору, который может отправлять информацию каждому отдельному подключенному клиенту (именно так мы сделали это с нашим Tcp-соединением, мы сохранили TcpClient и его основной поток в нашем классе StateObject, а затем связались с каждым клиентом через этипеременные. Я предполагаю, что это возможно и с сокетами?)

Теперь, когда вся информация сохранена, вы можете использовать ключи 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 из списка клиентов, где идентификаторбольше 5)

Если вы не хотите, чтобы идентификаторы идентифицировали клиентов таким образом, вы можете перебрать каждый StateObject в словаре и проверить внутренние переменные, чтобы увидеть, отправляете ли вы клиенту сообщение или нет.Что-то вроде:

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

Вам решать, какой метод лучше всего соответствует вашим потребностям.Надеюсь, что это помогает и является жизнеспособным решением для вас.

...