Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > Обмен сообщениями клиент-сервер


Автор: V0fka 15.2.2014, 17:37
Привет!

Что нужно сделать. На сервере крутится программа, которая принимает входящие подключения от клиентов и при возникновении определенного события - отсылает им сообщения. Клиенты принимают сообщения и как-то реагируют. Клиентов планируется на данном этапе порядка 100.

1) Сервер:

Сервер был сделан с помощью класса TcpListener. Далее в бесконечном цикле вызывается его метод AcceptTcpClient() и после полученный TcpClient добавляется в коллекцию clients. Это происходит не в основном потоке.

Для отправки сообщений в цикле обходится коллекция clients и для каждого элемента выполняется io = client.GetStream()  и потом io.Write(...);

2) Клиент:

Используется класс Socket. В бесконечном цикле выполняется метод Receive и тут же эти данные обрабатываются и выполняются какие-то действия. Это происходит не в основном потоке.

/////////////////

Я не особо шарю с C#, поэтому хотелось бы получить совет от людей, которые шарят, правильно ли выбрано направление для решения этой задачи:
1) Те ли классы я использую для сервера и клиента?
2) Если одновременно к серверу будет подключаться несколько клиентов, то используя в бесконечном цикле AcceptTcpClient() - я не пропущу никого из них?
3) Правильно ли на клиенте я "слушаю" сообщения? Меня смущает бесконечный цик там. Возможно это так делают, просто хочу узнать. Если же нет, то подскажите, пожалуйста, как надо.

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

Спасибо!

Автор: jonie 17.2.2014, 09:17
Цитата(V0fka @  15.2.2014,  18:37 Найти цитируемый пост)

1) Те ли классы я использую для сервера и клиента?

можно и эти. Кстати есть класс TcpClient раз уж пошла речь..

Цитата(V0fka @  15.2.2014,  18:37 Найти цитируемый пост)

2) Если одновременно к серверу будет подключаться несколько клиентов, то используя в бесконечном цикле AcceptTcpClient() - я не пропущу никого из них?

если не будете долго тупить в "добавлении клиентов в очередь" то не должны бы...

Цитата(V0fka @  15.2.2014,  18:37 Найти цитируемый пост)

3) Правильно ли на клиенте я "слушаю" сообщения? Меня смущает бесконечный цик там. Возможно это так делают, просто хочу узнать. Если же нет, то подскажите, пожалуйста, как надо.
вообще можно использовать асинхронное API, но если не критично то можно крутить и цикл.

Автор: V0fka 19.2.2014, 12:25
Цитата(jonie @  17.2.2014,  09:17 Найти цитируемый пост)
можно и эти. Кстати есть класс TcpClient раз уж пошла речь..

А какое преимущество TcpClient-а, в данном случае, будет?

Цитата(jonie @  17.2.2014,  09:17 Найти цитируемый пост)
если не будете долго тупить в "добавлении клиентов в очередь" то не должны бы...

Ясно, спасибо!

Цитата(jonie @  17.2.2014,  09:17 Найти цитируемый пост)
вообще можно использовать асинхронное API, но если не критично то можно крутить и цикл.

Правильно я вас понял, асинхронно - это, например, так: http://cyber-blog.klan-hub.ru/2010/08/28/асинхронная-работа-с-сокетами-в-c-шарп/  ? Если да, то у меня здесь появилась проблемка. В классе Server я подключенных клиентов собираю в коллекцию:

Код

private void AcceptCompleted(object sender, SocketAsyncEventArgs e)
 {
     if (e.SocketError == SocketError.Success)
     {
         Dispatcher.Invoke(...);
     }
     e.AcceptSocket = null;
     AcceptAsync(AcceptAsyncArgs);
 }


и у меня возникает ошибка, как здесь: http://forum.vingrad.ru/forum/topic-336459.html: Для нестатического поля, метода или свойства "System.Windows.Threading.Dispatcher.Invoke(System.Delegate, params object[])" требуется ссылка на объект.

Я её решил, передавая экземпляр Dispatcher в объект класса Server и соответственно вызываю Invoke через этот переданный диспатчер. Но, как всегда, есть сомнения насчет применения такого подхода. Хотелось бы получить "благословение" либо пинок в нужную сторону от знающих smile .

Автор: jonie 19.2.2014, 14:05
а зачем связывать очередь с UI ?!

Автор: V0fka 19.2.2014, 16:38
Сервер - это WPF приложение. На форме есть ListView, к которому биндится очередь и видно кто подключен сейчас.

Автор: jonie 19.2.2014, 17:52
Цитата(V0fka @  19.2.2014,  17:38 Найти цитируемый пост)
 На форме есть ListView, к которому биндится очередь и видно кто подключен сейчас.

и чО?
Очередь просто должна уметь уведомлять подписчиком что что-то поменялось, а те уже в своих обработчиках должны решать как на эти действия реагировать - плохая идея добавлять данные в UI потоке.

Автор: V0fka 21.2.2014, 10:07
Цитата(jonie @  19.2.2014,  17:52 Найти цитируемый пост)
и чО?

Я по вашему совету переделал сервер и клиент с использованием асинхронных методов. Конкретно сервер работает через AcceptAsync(...). И в результате когда хочу в коллекцию (а это ObservableCollection) добавить элемент, то Visual Studio говорит, что "нельзя добавить из этого потока" (ошибка не дословная, но я думаю, вы поняли что это). Тогда я нагуглил, что нужно добавлять через Dispatcher.Invoke. Попрбовал, но получил ошибку, которую выше озвчучил. После этого сделал так, как написал.

Цитата(jonie @  19.2.2014,  17:52 Найти цитируемый пост)
Очередь просто должна уметь уведомлять подписчиком что что-то поменялось, а те уже в своих обработчиках должны решать как на эти действия реагировать - плохая идея добавлять данные в UI потоке.

Можете пример какой-то привести, как это на примере WPF делается?

Автор: V0fka 21.2.2014, 11:19
По ходу разбирательств возник новый вопрос. Есть на сервере коллекция подключенных клиентов. В цикле обхожу её и методом Send хочу отправить сообщение. Все классно работает, если клиент подключен. Но если он отключен, то сервер виснет. Начал искать решения:
1) Установил на сервере в Socket.SendTimeout = 1, сделал через try catch отправку и если код попадает в catch - то клиент из коллекции удаляется. Подскажите, можно ли так делать, если планируется около 100 подключенных клиентов?
2) Обхожу коллекцию. Проверяю статус клиента IsConnected. Если IsConnected = false, то удаляю элемент из коллекции, если true, то отправляю сообщение. Но тут я заметил, что между проверкой и отправкой сообщения этот статус может поменяться и получается, что в момент Send клиента уже нету.
Вопрос: как правильно проверять активных клиентов, чтобы им дошли сообщения?

Автор: jonie 21.2.2014, 12:26
Цитата(V0fka @  21.2.2014,  11:07 Найти цитируемый пост)

Можете пример какой-то привести, как это на примере WPF делается? 

для .net 4.5 имеется http://msdn.microsoft.com/en-us/library/hh140164.aspx, а для других версий можно написать свою коллекцию же, с маршалингом вызовов callback делегатов в нужном SyncronizationContext-е.

Автор: V0fka 21.2.2014, 15:24
jonie, очередной раз я вам признателен за ответ, но что делать с BindingOperations.EnableCollectionSynchronization я в упор не пойму. Был бы очень признателен за примеры кода (псевдокода).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)