Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.80/5: Рейтинг темы: голосов - 5, средняя оценка - 4.80
3 / 3 / 0
Регистрация: 05.02.2017
Сообщений: 218

Чтение сообщений и отправка сообщений от нескольких клиентов

20.07.2023, 23:16. Показов 1190. Ответов 9
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день. Пишу учебный сервер чат мессейджер через TcpListener.

Когда запускается сервер и клиент, чат работает, основную функцию выполняет. Реализованно если кратко так

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
                TcpClient clientSocker = await serverSocket.AcceptTcpClientAsync();
 
                NetworkStream stream = clientSocker.GetStream();
                byte[] bytes = new byte[256];
                while (true)
                {
 
                    ReadAsync(stream, bytes);
                    SendAsync(stream);
                }
 
 
        static void Send_MSG(NetworkStream stream)
        {
            string message = Console.ReadLine();
            byte[] bytesWrite = Encoding.UTF8.GetBytes(message);
            stream.Write(bytesWrite, 0, bytesWrite.Length);
            stream.Flush();
        }
 
        static void Read_MSG(NetworkStream stream, byte[] bytes)
        {
            var count = stream.Read(bytes, 0, bytes.Length);
            string request = Encoding.ASCII.GetString(bytes, 0, count);
            Console.WriteLine("Klient:" + request);
        }
 
        static async Task SendAsync(NetworkStream stream)
        {
            await Task.Run(() => Send_MSG(stream));
        }
 
        static async Task ReadAsync(NetworkStream stream, byte[] bytes)
        {
            await Task.Run(() => Read_MSG(stream,bytes));
        }
Суть вопроса, подскажите пожалуйста, как мне реализовать, чтобы сервер когда отправлял сообщения отправлял их каждому клиенту, или соответственно принимать от двух и более клиентов сообщения на сервер.

Я примерно понимаю, что
C#
1
    NetworkStream stream = clientSocker.GetStream();
и дальнейшие методы для отправки сообщений и приема используют стрим именно первого подключения, но не представляю как реализовать даже. Использовать в метотах что то вроде ReadAsync? но методы же итак асинхронны. Просьба направить и объяснить пожалуйста. Заранее благодарен
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
20.07.2023, 23:16
Ответы с готовыми решениями:

Отправка нескольких CAN сообщений
Начал разбираться с CAN (STM32F103RBT6). Для отладки - настроил в режиме LoopBack, также в этом режиме сообщения отправляются и...

Отправка нескольких сообщений через QTcpSocket
Имеется множество строк QString возвращаемых из БД. После каждого возвращения строка сериализуется QDataStream-ом в QByteArray и...

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

9
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
21.07.2023, 00:56
Цитата Сообщение от KAPATEJlb Посмотреть сообщение
Суть вопроса, подскажите пожалуйста, как мне реализовать, чтобы сервер когда отправлял сообщения отправлял их каждому клиенту, или соответственно принимать от двух и более клиентов сообщения на сервер.
  • При подключении нового клиент, запоминаете его в колекцию.
  • При отключении -- удаляете
  • коллекция должна быть потокобезопасной (List<T> -- не потокобезопасный)
  • Когда приходит сообщение от одного клиента, проходите по всей коллекции, проверяете что это не оригинальный отправитель, и пересылаете сообщение
  • При выполнении перебора, учитывайте что в этот момент может прийти новое (от/под)ключение, а значит коллекция изменится (List<T> при изменении в foreach выдаст ошибку. Тоже самое может случится при использовании for -- либо выйдете за границы, либо обработаете не всех из-за вклиневшегося)

Для начала рекомендую таки почитать про потокобезопасные коллекции на C# (в гугл, мне лень искать сейчас), и только потом пытаться что-то реализовывать.
0
3 / 3 / 0
Регистрация: 05.02.2017
Сообщений: 218
21.07.2023, 11:09  [ТС]
Цитата Сообщение от Wolfdp Посмотреть сообщение
Для начала рекомендую таки почитать про потокобезопасные коллекции на C#
Спасибо почитаю, но все таки вопрос у меня остается актуальным, т.к я стараюсь все так сказать прощупать, а вопрос в том, по какому свойству можно обращаться к асинхронному потоку?
Ну то есть код -то один, но его могут использовать несколько пользователей. Вот как мне например обратиться перед занесем в коллекцию отдельно на примере двух пользователей, например пользователь1 и пользователь2. Как система их распределяет, по какому свойству...
Это не очень понимаю.
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
21.07.2023, 12:40
KAPATEJlb, окей, начнем с супер основ: два потока Threаd (даже не асинхроных, вот прям new Thread и погнали). В каждом потоке есть цикл от 0 до 100. Вам нужно из каждого потока в общую коллекцию записать от 0 до 100 (очередность не имеет значение). Как вы для этих двух потоков организуете общую коллекцию?

Тоже самое будет и для подключенных клиентов: они будут обрабатывать входящие данные в своем потоке, но где-то там у вас объявлена общая коллекция (скажем через тот же static, то это нубский вариант), к которой и идет обращение.
0
3 / 3 / 0
Регистрация: 05.02.2017
Сообщений: 218
21.07.2023, 14:53  [ТС]
да, мне нужны супер основы)

Ваши слова мне вроде как понятны, но как я понимаю в данном примере просто созданы два потока-функции которые заполняют коллекцию. Но вопрос мой наверное более противоположный. Например как мне создать ТРЕТЬЮ функцию, не в которую, а которая сама будет обращаться к потоку один или потоку два и брать от туда информацию.
Самый банальный пример в потоке один хранится переменная "result=one". В потоке два хранится переменная "result=two"

как мне из третьего метода обратиться к каждому из потоков, чтобы переменную из нужного мне примера. Может пример грубый и не правильный, не спорю, но пытаюсь разобраться)
Цитата Сообщение от Wolfdp Посмотреть сообщение
Тоже самое будет и для подключенных клиентов: они будут обрабатывать входящие данные в своем потоке, но где-то там у вас объявлена общая коллекция (скажем через тот же static, то это нубский вариант), к которой и идет обращение.
Потому как я понимаю в вашем примере каждый из потоков берет коллекцию, проверяет и добавляет. А мне нужно скажем так третий метод, который будет выбирать нужную информацию из двух потоков.

Добавлено через 6 минут
Потому что например сервер из моего учебного проекта. У меня получается отправлять сообщения только первому клиенту, а если я буду добавлять в коллекцию и отправлять всем элементам в коллекции, то какое свойство мне брать для рассылки.
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
21.07.2023, 16:13
Лучший ответ Сообщение было отмечено KAPATEJlb как решение

Решение

Ух... очень сложно понять ваше сообщение, плюс сам могучий русский под "потоком" может подразумевать как Thread, так и Stream... Вот самый банальный (и не правильный) пример многопоточного подключения

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var list = new List<TcpClient>();
 
while(true)
{
    var client = new server.AcceptTcpClient();
    list.Add(client);
    StartNewSession(client);
}
 
void StartNewSession(TcpClient current)
{
 
new Thread(()=>{
 
    do
    {
        var message = Read();
        if(message == null)
            continue;
        foreach(var otherClient in clinet.Where(c => c != current))
            otherClient.Write(message)
    }
while(message != null);
 
});
 
}
Ваш код
C#
1
2
3
4
5
6
7
8
9
10
11
12
                TcpClient clientSocker = await serverSocket.AcceptTcpClientAsync(); //получили новое подключение
 
//нет выделения нового потока Thread под подключение
 
                NetworkStream stream = clientSocker.GetStream();
                byte[] bytes = new byte[256];
                while (true)
                {
 
                    ReadAsync(stream, bytes); // считали сообщение
                    SendAsync(stream); //отправили ему же
                }
Если у вас нет понимания что такое Thread -- бесполезно пытаться что-то делать.
1
3 / 3 / 0
Регистрация: 05.02.2017
Сообщений: 218
22.07.2023, 18:14  [ТС]
Цитата Сообщение от Wolfdp Посмотреть сообщение
Если у вас нет понимания что такое Thread -- бесполезно пытаться что-то делать.
Спасибо вам большое за этот код, честно говоря не все сделал как вы написали, и что то да не понял, но саму суть кажется уловил, сейчас добился то чего хотел, да и поразбирал пришел к какому то пониманию. Насчет небезопасной коллекции вкурсе, но делал для банального примера.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
            serverSocket.Start();//запускаем сервер
            Console.WriteLine("Server started");
            var list = new List<TcpClient>();
 
            byte[] bytes = new byte[256];
            while (true)
            {
                TcpClient clientSocker = serverSocket.AcceptTcpClient();
                list.Add(clientSocker);
                NetworkStream stream = clientSocker.GetStream();
                ReadAsync(stream, bytes);//читаю стрим от каждого
                SendAsync(list);
            }
 
 
   static void Send_MSG(List<TcpClient> list)
        {
            while (true)
            {
                string message = Console.ReadLine();
                byte[] bytesWrite = Encoding.UTF8.GetBytes(message);
                foreach(var otherClient in list)
                {
                    NetworkStream stream= otherClient.GetStream();
                    stream.Write(bytesWrite, 0, bytesWrite.Length);
                    stream.Flush();
                }
                Task.Delay(200).Wait();
            }
        }
То есть я создал коллекцию в которую добавляются подключения, и уже в асинхронном постоянном методе отправки сообщения перебираю клиентов, и отправляю нужному.
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
22.07.2023, 23:33
Цитата Сообщение от KAPATEJlb Посмотреть сообщение
но саму суть кажется уловил
к сожалению нет. Вот этот код -- абсолютно неправильный
Цитата Сообщение от KAPATEJlb Посмотреть сообщение
C#
1
2
ReadAsync(stream, bytes);//читаю стрим от каждого
SendAsync(list);
- общий буффер для ВСЕХ подключений. Вам не кажется что если одновременно придет запись от двух клиентов, то будет беда?
- отправлка где-то в другом потоке, которая по идеи зависит от Task.Delay(200). Вообще, если вы для синхронизации ставите Delay -- уже не правильно. Для этого существуют мютексы/семафоры/ивенты.

Отправка сообщения должна быть в том же потоке, где идет считывание. Т.е. нужно слиять ReadAsync и SendAsync в единый метод.

Вся сложность таких многопоточных приложений в том, что ошибки "плавающие". Т.е. запустив один раз на "проверить", вы скорее всего не отловите ошибку, но это не гарантирует стабильную работу от слова "совсем".
0
3 / 3 / 0
Регистрация: 05.02.2017
Сообщений: 218
23.07.2023, 13:11  [ТС]
Цитата Сообщение от Wolfdp Посмотреть сообщение
- общий буффер для ВСЕХ подключений. Вам не кажется что если одновременно придет запись от двух клиентов, то будет беда?
да, уже нашел ошибку и логику при общении двух клиентов, да и зачем я дублирую на сервере каждый раз асинхронные методы при подключении клиента, уже вылилось в ошибки)

Цитата Сообщение от Wolfdp Посмотреть сообщение
Task.Delay(200)
а это я делал, чтобы процессор не нагружался)
Спасибо вам, работаю над ошибками и осмысливаю)

Добавлено через 2 минуты
Цитата Сообщение от Wolfdp Посмотреть сообщение
ReadAsync и SendAsync в единый метод.
честно говоря, не очень понимаю, как это реализовать возможно, ведь получится что чтения на определенном этапе не получится, ведь машина будет ждать ввода текста console.ReadLine, или же, я еще про них не читал использовать что то вроде stream.ReadAsync?
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
26.07.2023, 09:01
Цитата Сообщение от KAPATEJlb Посмотреть сообщение
честно говоря, не очень понимаю, как это реализовать возможно, ведь получится что чтения на определенном этапе не получится, ведь машина будет ждать ввода текста console.ReadLine,
На сервере есть N-сокетов, подключенных к клиентам. Каждый в режиме ожидания чтения сообщения. Это сообщение появится там только когда какой-то из клиентов на своей стороне что-то отправит. И только тогда вы перешлете это сообщение всем остальным. Это нормальная ситуация для сервака.

Не по теме:

У меня впечатление, что вы в каком-то авральном режиме проходите курс по C#, и у вас не успевает устаканиваться базовая инфа с предыдущих тем, а какие-то вы либо пропустили, либо порядок обучения у вас не правильный.

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
26.07.2023, 09:01
Помогаю со студенческими работами здесь

Отправка последовательно нескольких сообщений в Telegram Bot
Приветствую, Пишу бота на PHP для Telegram и столкнулся с проблемой, что надо отправить массив информации НЕ одним сообщением, а разбить...

TcpServer. Прием сообщений от клиентов
Доброго времени суток. Есть сервер: #include &quot;server.h&quot; #include &quot;ui_server.h&quot; #include &quot;QMessageBox&quot; ...

Совмещение кастомных сообщений об ошибках и подробных сообщений, возможно ли это?
Доброго времени суток! Сразу скажу,что только недавно познакомился с IIS 7.5. Вопрос такой, у iis есть возможность использовать...

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

Отправка сообщений на IP
через ClientSocket, Server Socket уже сделал возможным пересылку сообщений. Пытался улучшить программу, но ф-ю SendMessageToIP() билдер...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru