powered by simpleCommunicator - 2.0.18     © 2024 Programmizd 02
Map
Форумы / WCF, Web Services, Remoting [игнор отключен] [закрыт для гостей] / Асинхронная отправка сообщений WCF пользователям чата
11 сообщений из 11, страница 1 из 1
Асинхронная отправка сообщений WCF пользователям чата
    #40115033
Naudachu
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Реализовал метод асинхронной отправки сообщений клиентам, но он отправляет это сообщение абсолютно всем, в том числе и самому отправителю.

Как сделать так чтобы сообщение приходило всем кроме отправителя?

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
            public void AddMessage(byte[] message)
           {
                
                  IAsyncMessageCallback other = OperationContext.Current.GetCallbackChannel<IAsyncMessageCallback>();
                  other.BeginOnMessageAdded(message, DateTime.Now, delegate (IAsyncResult ar)
                        {
                            other.EndOnMessageAdded(ar);
                        }, null);
                
 
            }


Попытался сделать вот так, но получаются жутки тормоза при подключении больше двух клиентов и в конце концов разрыв канала передачи( без foreach разрывов нет)


Код: 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.
Dictionary<IAsyncMessageCallback, string> subscribers = new Dictionary<IAsyncMessageCallback, string>();
            public void Join(string username)
            {
                var connection = OperationContext.Current.GetCallbackChannel<IAsyncMessageCallback>();
                subscribers[connection] = username;
 
            }
            public void AddMessage(byte[] message)
            {
                lock (subscribers)
                {
                    var connection = OperationContext.Current.GetCallbackChannel<IAsyncMessageCallback>();
 
                    string user;
                    if (!subscribers.TryGetValue(connection, out user))
                        return;
                    foreach (var other in subscribers.Keys)
                    {
                        //Console.WriteLine(other + " " + connection);
                        if (other == connection)
                            continue;
                        Console.WriteLine(other + " " + connection);
                        other.BeginOnMessageAdded(message, DateTime.Now, delegate (IAsyncResult ar)
                        {
                            other.EndOnMessageAdded(ar);
                        }, null);
                        Console.WriteLine(message.Length);
                    }
                }
              }



Реализация не асинхронной отправки


Код: 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.
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
    public class ChatServiceg : IChatService
    {
        Dictionary<IChatClient, string> _users = new Dictionary<IChatClient, string>();
        public void Join(string username)
        {
            var connection = OperationContext.Current.GetCallbackChannel<IChatClient>();
            _users[connection] = username;
        }
 
        public void SendMessage(byte[] message)
        {
            var connection = OperationContext.Current.GetCallbackChannel<IChatClient>();
            string user;
            if (!_users.TryGetValue(connection, out user))
                return;
             foreach (var other in _users.Keys)
            {
                if (other == connection)
                    continue;
                other.RecievMessage(user, message);
                Console.WriteLine(message.Length);
            }
        }
    }



В переменной connection храниться пользователь который вызвал этот метод(отправил свой аудиопоток)- далее сообщение
В _users хранятся все подключённые пользователи
Принцип работы метода SendMessage:
1. в connection записывается пользователь который отослал сообщение
2. в цикле foreach переменной other присваиваются каждый пользователь чата, если other==connection то получается отправлять сообщение пользователю other не надо т.к. он сам его отправил.

Суть проблемы:
1.При заходе больше двух пользователей чат начинает подвисать(очень большая задержка появляется), а потом обрыв соединения: Коммуникационный объект System.ServiceModel.Channels.ServiceChannel нельзя использовать для связи, так как его работа прервана

2.Если убрать цикл foreach, то обрывов не будет и чат будет спокойно работать с 10+ пользователей, но сообщение будет отсылаться всем ( то есть я в чате буду слышать свой голос)







Клиентская часть, используется библиотека Naudio

Код: 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.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
public class MyCallback : Proxy.IChatServiceCallback
    {
        public void RecievMessage(string user, byte[] message)
        {
           output.Play();
            try
            {
                //получено данных
                int received = message.Length;
                //добавляем данные в буфер, откуда output будет воспроизводить звук
                bufferStream.AddSamples(message, 0, received);
            }
            catch
            { }
        }
 
        public static WaveInEvent input;
        //поток для речи собеседника
        public static WaveOutEvent output;
        //буфферный поток для передачи через сеть
        public static BufferedWaveProvider bufferStream;
        public static InstanceContext context = new InstanceContext(new MyCallback());
        public static ChatServiceClient server = new ChatServiceClient(context);
        private static void Voice_Input(object sender, WaveInEventArgs e)
        {
            try
            {
                server.SendMessage(e.Buffer);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message+" wasdad");
            }
        }
        static void Main(string[] args)
        {
            try
            {
                for (int n = 0; n < WaveIn.DeviceCount; n++)
                {
                    var capabilities = WaveIn.GetCapabilities(n);
                    Console.WriteLine( capabilities.ProductName);
                }
                input = new WaveInEvent();
                input.DeviceNumber = 0;
                //определяем его формат - частота дискретизации 8000 Гц, ширина сэмпла - 16 бит, 1 канал - моно
                input.WaveFormat = new WaveFormat(8000, 16, 1);
                //добавляем код обработки нашего голоса, поступающего на микрофон
                input.DataAvailable += Voice_Input;
                //создаем поток для прослушивания входящего звука
                output = new WaveOutEvent();
                //создаем поток для буферного потока и определяем у него такой же формат как и потока с микрофона
                bufferStream = new BufferedWaveProvider(new WaveFormat(8000, 16, 1));
                //привязываем поток входящего звука к буферному потоку
                output.Init(bufferStream);
                Console.WriteLine("enter username");
                var username = Console.ReadLine();
                server.Join(username);
                Console.WriteLine();
                input.StartRecording();
                //Console.WriteLine("Enter message");
                Console.WriteLine("Press Q to Exit");
                var message = Console.ReadLine();
            }
            catch { };
        }
    }
...
Рейтинг: 0 / 0
Асинхронная отправка сообщений WCF пользователям чата
    #40115210
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Может для начал проще сделать так:
пусть отправитель не парится, а шлет быстро и всем, а уже получатель фильтрует
...
Рейтинг: 0 / 0
Асинхронная отправка сообщений WCF пользователям чата
    #40115221
Naudachu
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ролг Хупин, А как можно фильтровать байтовый массив который отсылает сервер клиенту?
...
Рейтинг: 0 / 0
Асинхронная отправка сообщений WCF пользователям чата
    #40115241
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Naudachu
Ролг Хупин, А как можно фильтровать байтовый массив который отсылает сервер клиенту?



Добавьте try catch и покажите подробности этой ошибки
"Коммуникационный объект System.ServiceModel.Channels.ServiceChannel нельзя использовать для связи, так как его работа прервана"
...
Рейтинг: 0 / 0
Асинхронная отправка сообщений WCF пользователям чата
    #40115267
Naudachu
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ролг Хупин, Сервер из за проверки foreach+if:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
            var connection = OperationContext.Current.GetCallbackChannel<IChatClient>();            
            foreach (var other in _users.Keys)
            {
                if (other == connection)
                    continue;
                other.RecievMessage(" ", message);
                
            }


не успевает рассылать сообщения. При двух пользователях всё работает прекрасно, при больше чем 2 пользователя сервер перестаёт отвечать(Коммуникационный объект System.ServiceModel.Channels.ServiceChannel нельзя использовать для связи, так как его работа прервана).

Если убрать проверку, то есть оставить вот так:
Код: c#
1.
2.
3.
4.
5.
            
                var connection = OperationContext.Current.GetCallbackChannel<IChatClient>();
                connection.RecievMessage(" ", message);
                
            }



То всё работает стабильно даже с 10 пользователями, но соответственно они слышат сами себя т.к. нет проверки
if (other == connection) и следовательно сервер отправляет это сообщение всем
...
Рейтинг: 0 / 0
Асинхронная отправка сообщений WCF пользователям чата
    #40115331
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Naudachu
Ролг Хупин, Сервер из за проверки foreach+if:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
            var connection = OperationContext.Current.GetCallbackChannel<IChatClient>();            
            foreach (var other in _users.Keys)
            {
                if (other == connection)
                    continue;
                other.RecievMessage(" ", message);
                
            }


не успевает рассылать сообщения. При двух пользователях всё работает прекрасно, при больше чем 2 пользователя сервер перестаёт отвечать(Коммуникационный объект System.ServiceModel.Channels.ServiceChannel нельзя использовать для связи, так как его работа прервана).

Если убрать проверку, то есть оставить вот так:
Код: c#
1.
2.
3.
4.
5.
            
                var connection = OperationContext.Current.GetCallbackChannel<IChatClient>();
                connection.RecievMessage(" ", message);
                
            }



То всё работает стабильно даже с 10 пользователями, но соответственно они слышат сами себя т.к. нет проверки
if (other == connection) и следовательно сервер отправляет это сообщение всем


Странно, при чем тут проверка.
Написано "сервер отправляет это сообщение всем", но тут получение?

А так:
foreach (var other in _users.Keys)
{
if (other != connection)
other.RecievMessage(" ", message);
}
...
Рейтинг: 0 / 0
Асинхронная отправка сообщений WCF пользователям чата
    #40115335
Naudachu
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ролг Хупин, RecievMessage - метод контракта обратного вызова.
Клиент чтобы отправляет сообщение вызывает метод void SendMessage(byte[] message) реализованный на сервере и передаёт записанный массив байтов.

При вызове метода SendMessage сервер вызывает метод RecievMessage(" ", message) реализованный на клиенте, при этом передаёт в него массив байтов звука. Когда метод RecievMessage вызывается на клиенте он воспроизводит этот массив байтов.
Так работает дуплексные службы https://docs.microsoft.com/ru-ru/dotnet/framework/wcf/feature-details/duplex-services


Но чтобы сервер не отсылал массив байтов клиенту который его же и отправил был реализован алгоритм проверки (ваш алгоритм безусловно верен):
Код: c#
1.
2.
3.
4.
5.
foreach (var other in _users.Keys)
{
if (other != connection)
other.RecievMessage(" ", message);
}



1. НО если подключаться больше двоих клиентов, то звук начнёт подвисать очень сильно


2. НО если убрать этот алгоритм проверки, то хот 10 человек подключаться и всё будет работать, за исключением того, что они слышат сами себя

Если я прикреплю проект, это даст резултат?
...
Рейтинг: 0 / 0
Асинхронная отправка сообщений WCF пользователям чата
    #40115474
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Naudachu
Ролг Хупин, RecievMessage - метод контракта обратного вызова.
Клиент чтобы отправляет сообщение вызывает метод void SendMessage(byte[] message) реализованный на сервере и передаёт записанный массив байтов.

При вызове метода SendMessage сервер вызывает метод RecievMessage(" ", message) реализованный на клиенте, при этом передаёт в него массив байтов звука. Когда метод RecievMessage вызывается на клиенте он воспроизводит этот массив байтов.
Так работает дуплексные службы https://docs.microsoft.com/ru-ru/dotnet/framework/wcf/feature-details/duplex-services


Но чтобы сервер не отсылал массив байтов клиенту который его же и отправил был реализован алгоритм проверки (ваш алгоритм безусловно верен):
Код: c#
1.
2.
3.
4.
5.
foreach (var other in _users.Keys)
{
if (other != connection)
other.RecievMessage(" ", message);
}




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


1. НО если подключаться больше двоих клиентов, то звук начнёт подвисать очень сильно


2. НО если убрать этот алгоритм проверки, то хот 10 человек подключаться и всё будет работать, за исключением того, что они слышат сами себя

Если я прикреплю проект, это даст резултат?
...
Рейтинг: 0 / 0
Асинхронная отправка сообщений WCF пользователям чата
    #40116234
Naudachu
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ролг Хупин, я осознал свою ошибку, мне нужно сделать этот метод асинхронным:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
        
         public void SendMessage(string message, string name)
        {
            var connection = OperationContext.Current.GetCallbackChannel<IChatClient>();
            string user;
            if (!_users.TryGetValue(connection, out user))
                return;
            foreach (var other in _users.Keys)
            {
                if (other == connection)
                    continue;
                other.RecievMessage(user, message);
            }
        }



Перепробовал множество вариантов, но не получается
...
Рейтинг: 0 / 0
Асинхронная отправка сообщений WCF пользователям чата
    #40116291
Naudachu
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ролг Хупин, Можешь помочь?
...
Рейтинг: 0 / 0
Асинхронная отправка сообщений WCF пользователям чата
    #40116423
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Naudachu
Ролг Хупин, Можешь помочь?


Пытаюсь всеми силами
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / WCF, Web Services, Remoting [игнор отключен] [закрыт для гостей] / Асинхронная отправка сообщений WCF пользователям чата
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали тему (1): Анонимы (1)
Читали форум (1): Анонимы (1)
Пользователи онлайн (10): Анонимы (9), Yandex Bot
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]