Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.54/37: Рейтинг темы: голосов - 37, средняя оценка - 4.54
 Аватар для m0nax
1274 / 975 / 113
Регистрация: 12.01.2010
Сообщений: 1,971

Асинхронный сервер - чат, много сообщений

02.06.2010, 19:32. Показов 7605. Ответов 9
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
вобщем сделал некое подобие чата, все вроде бы хорошо - отсылает/принимает сообщения нормально от множества клиентов

придумал некую эмуляцию большой нагрузки
C#
1
2
3
4
5
                            for (int i = 0; i < 100; ++i)
                            {
                                client.Send("test message " + i);
                                //Thread.Sleep(150);
                            }
в итоге сообщения сливаются в строки типа "test message 1test message 2test message 3" и т.д

если включить Sleep и пробовать на 2 разных компах в сети глюк остается, но через 127.0.0.1 глюка нет
а если без задержки то даже через 127.0.0.1 сливаются



серверная часть часть выглядит так
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
    class AsyncServer
    {
        int port = 5691;
        object locker = new object();
 
        //IPHostEntry host;
        IPAddress addr;
        Socket _mainSocket;
        List<User> connections = new List<User>();
 
        public AsyncServer()
        {
            //host = Dns.GetHostEntry(Dns.GetHostName());
            //foreach (var v in host.AddressList)
            //  Console.WriteLine(v);
            
            addr = IPAddress.Loopback;//host.AddressList[3];
 
            SetServer();
            StartAsync();
        }
        private void SetServer()
        {
            _mainSocket = new Socket(addr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            _mainSocket.Bind(new IPEndPoint(addr, port));
            _mainSocket.Listen(10);
            Console.WriteLine("сервер запущен на {0}", _mainSocket.LocalEndPoint);
        }
 
        private void StartAsync()
        {
            for (int i = 0; i < 10; ++i)
                _mainSocket.BeginAccept(null, 1024, new AsyncCallback(AcceptCallback), _mainSocket);
        }
 
        private void AcceptCallback(IAsyncResult ar)
        {
            User _user = new User();
            _user.Buffer = new byte[256];
 
            try
            {
                Socket socket = (Socket)ar.AsyncState;
 
                int countBytes = -1;
                byte[] buff;
                _user.socket = socket.EndAccept(out buff, out countBytes, ar);
                if (countBytes > 0)
                {
                    string[] nameAndPass = Encoding.UTF8.GetString(buff, 0, countBytes).Split('&');
 
                    _user.uName = nameAndPass[0];
                    _user.uPassword = nameAndPass[1];
                }
 
                //Console.WriteLine("установленно соединение с {0}  {1} >> {2}",
                // _user.socket.RemoteEndPoint, _user.uName, _user.uPassword);
 
                lock (locker)
                    connections.Add(_user);
 
                _user.socket.BeginReceive(_user.Buffer, 0, _user.Buffer.Length,
                    SocketFlags.None, new AsyncCallback(ReceiveCallback), _user);
 
                socket.BeginAccept(null, 1024, new AsyncCallback(AcceptCallback), _mainSocket);
 
                SendSystemMMessage("Вошел в чат", _user);
            }
            catch (SocketException sExept)
            {
                Console.WriteLine(sExept.ErrorCode);
            }
            catch (SystemException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
 
        private void ReceiveCallback(IAsyncResult ar)
        {
            User user = (User)ar.AsyncState;
 
            try
            {
                int bytesCount = user.socket.EndReceive(ar);
 
                if (bytesCount != 0) 
                {
                    string text = Encoding.UTF8.GetString(user.Buffer, 0, bytesCount);
 
                    if (text == "exit")
                    {
                        CloseConnect(user);
                        return;
                    }
 
                    Console.WriteLine(text);
 
                    lock (locker)
                        foreach (User client in connections)
                        {
                            client.socket.Send(user.Buffer, 0, bytesCount, SocketFlags.None);
                        }
                    user.socket.BeginReceive(user.Buffer, 0, user.Buffer.Length, SocketFlags.None,
                        new AsyncCallback(ReceiveCallback), user);
                }
                else CloseConnect(user);
 
            }
            catch (SocketException ex)
            {
                if (ex.ErrorCode == 10054)
                {
                    CloseConnect(user);
                    SendSystemMMessage("(SocketException) Вышел из чата ", user);
                }
            }
        }
 
        private void CloseConnect(User _user)
        {
            _user.socket.Close();
 
            lock (locker)
                connections.Remove(_user);
 
            SendSystemMMessage("Вышел из чата ", _user);
        }
 
        private void SendSystemMMessage(string msg, User from)
        {
            Console.WriteLine(from.uName + "  " + msg);
 
            byte[] tempBuf = Encoding.UTF8.GetBytes(string.Format("{0} " + msg, from.uName));
 
            lock (locker)
                foreach (var clinet in connections)
                    clinet.socket.Send(tempBuf, 0, tempBuf.Length, SocketFlags.None);
        }
 
        //private void SendCallback(IAsyncResult ar)
        //{
        //    ((Socket)ar.AsyncState).EndSend(ar);
        //}
 
        class User
        {
            public string uName;
            public string uPassword;
            public Socket socket;
            public byte[] Buffer;
        }
    }
бьюсь пол дня, чего только не пробовал уже - все равно сообщения сливаются...
вот я думаю возможно ли это вообще вылечить? может такой поток сообщений и не должно выдерживать?

да и кстати говоря - нормально ли делать такой прием имени юзера и пароля? выглядит как-то не очень надежно...как лучше?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
02.06.2010, 19:32
Ответы с готовыми решениями:

Принятие сообщений от сервера в бесконечном цикле (Клиент-Сервер Чат)
Если кто то написал сообщение то это сообщение обрабатывает сервер и рассылает всех клиентам.. Но проблема в том что не понимаю как...

Простенький асинхронный чат. Что-то не то с кодировкой
Нашел пример простого чата. В комплект поставки входит серверная чать и клиентская (исходник в аттаче). Запустил, вроде все работает. При...

Асинхронный сервер
всем привет. У меня есть асинхронный сервер, который получает данные следующим образом: private void OnRecieved(IAsyncResult ar) { ...

9
 Аватар для HIMen
4340 / 1509 / 101
Регистрация: 12.04.2009
Сообщений: 2,342
02.06.2010, 19:35
Вроде все правильно, шлешь данные с малым интервалом - он отправляет их в одном пакете.
Либо ставь Sleep, либо добавляй в конце каждого сообщения разделитель, чтобы уметь отделять их друг от друга
0
 Аватар для m0nax
1274 / 975 / 113
Регистрация: 12.01.2010
Сообщений: 1,971
02.06.2010, 19:45  [ТС]
как я и думал...

а как вообще работает метод Send у сокета -
отправляет данные в сеть, ждет пока их примут и только тогда завершается
или просто отправляет и завершается?

и в чем смысл BeginSend, т.е он ждет чего перед отравкой - освобождения сети, времени проца или как?
0
1 / 1 / 0
Регистрация: 03.06.2010
Сообщений: 7
03.06.2010, 07:55
Привет. Тоже пишу подобный сервер. Попробуй для каждого подключения делать свой поток.

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

В C# где-то недельку, но с программированием знаком хорошо ибо без труда написал TCP сервер.. Вот только прочтя эту тему(проделав проверку) заметил, что подобная проблема с совмещением сообщений...

Будто буфер получая сообщение в единицу времени склеивает их =(
0
7 / 7 / 0
Регистрация: 06.02.2010
Сообщений: 31
03.06.2010, 09:11
я у сервера делал по по-потоку на каждого клиента (по-сути не совсем корректный подход, ибо при 1000 коннектов сервер будет тормозить). Все сообщения приходящие от пользователей кидались в очередь. Основной поток сервера извлекал сообщения из очереди и транслировал всем клиентам.
0
1 / 1 / 0
Регистрация: 03.06.2010
Сообщений: 7
03.06.2010, 11:49
А какой способ корректнее? Я лично тоже так делаю, новый пользователь - новый поток.

Действительно, мне помог вариант с разделением строки по символу! К примеру вот как я реализовал:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
while ((bytesRcvd = User.Receive(MessageBuffer, MessageBuffer.Length, SocketFlags.None)) > 0 && User.Connected) {
                    TotalBytes += bytesRcvd;
 
                    Random RND = new Random();//Симулируем лаги
                    int RNDNum = RND.Next(20000000);
                    for (int blabla = 0; blabla < 10000000 + RNDNum; blabla++) {
                        int gg = blabla;
                    }
 
                    Message = Encoding.UTF8.GetString(MessageBuffer, 0, bytesRcvd);
                    //Console.WriteLine(Message + " " + bytesRcvd);
                    String[] MessageArr = Message.Split('\0');
                    foreach (String TM in MessageArr) {
                        if (TM.Length > 0) {
                            Message = TM+"\0";
                            MessageData = Encoding.UTF8.GetBytes(Message);
 
                            Console.WriteLine(Message + " " + Message.Length + " " + bytesRcvd);
Так как мой клиент на Flash, он в конце каждой строки пишет символ новой строки \0, благодоря этому легко делить =) Но надо не забыть после разделения вернуть \0 в строку =)

Спасибо HIMen за идею с разделением =)
0
7 / 7 / 0
Регистрация: 06.02.2010
Сообщений: 31
03.06.2010, 12:16
Цитата Сообщение от FDoKE Посмотреть сообщение
А какой способ корректнее? Я лично тоже так делаю, новый пользователь - новый поток.
По большому счету выгоднее наверное сделать один поток на прослушку уже подключенных клиентов (последовательно перебирать коннекты и для каждого из них вытаскивать данные из его же потока), а второй поток для создания новых подключений. При таком подходе ресурсов нужно гораздо меньше, да и отклик не должен пострадать
0
 Аватар для m0nax
1274 / 975 / 113
Регистрация: 12.01.2010
Сообщений: 1,971
03.06.2010, 16:51  [ТС]
выгодней использовать как раз асинхронные операции, как собственно у меня и сделано

судя по статье http://www.microsoft.com/Rus/M... nsock.mspx такой подход по всем параметрам лучше

вообще по теме я уже вычитал на мсдн описание методов сокетов, там как раз сказано что они не гарантируют моментальную отправку данных, а могут ждать заполнения буфера
0
1 / 1 / 0
Регистрация: 03.06.2010
Сообщений: 7
03.06.2010, 18:09
Тоесть? А каким методом он определяет когда отправлять, а когда нет? x))) Хм, а если нужна моментальная?
0
 Аватар для m0nax
1274 / 975 / 113
Регистрация: 12.01.2010
Сообщений: 1,971
03.06.2010, 18:20  [ТС]
точней отправку-то они гарантируют почти всегда, а вот именно доставки до места назначения может и не быть сразу
там есть какой-то "неблокирующий режим" еще...думаю можно настроить чтоб сразу отправлялось

вообще там все написано http://msdn.microsoft.com/ru-r... yy28a.aspx
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
03.06.2010, 18:20
Помогаю со студенческими работами здесь

Асинхронный клиент-сервер
Здравствуйте. Вот уже 3 дня бьюсь над проблемой, решение которой не могу найти. Вообщем, коротко говоря, имеется серверное приложение,...

Асинхронный сервер не отвечает
Добра. Написал асинхронных сервер сервер и клиент для чата. Порядок работы примерно таков: Клиент подключается к серверу Сервер...

Асинхронный сервер на UDP-сокетах
Хай. Я как-то писал асинх. сервер с использованием TCP-протокола и все получилось очень круто, потому что там есть понятие соединения, и...

Асинхронный сокет сервер + SSL
Здравствуйте. Требуется написать асинхронный сервер + ssl. С этим(...

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


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru