Модераторы: Partizan, gambit

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Пул потоков... 
:(
    Опции темы
STRELOKBMSTU
Дата 11.1.2010, 12:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 11.8.2007
Где: Russia.MR.Moscow( );

Репутация: нет
Всего: нет



Нужно создать что-то типа пула потоков внутри Win-сервиса. Пользователи будут подключаться к серверу, регистрироваться на нем, будет создаваться отдельный поток, а в нем сокет для дальнейшего обмена информацией... Соответственно на сервере должен быть список пользователей с ключами и информацией о пользователе, к примеру Dictionary<GUID,UserObject>... в случае необходимости отпраки сообщения по ключу, сервис обращается к нужному потоку и отправляет сообщения на нужный сокет... 

В общем так мне видится реализация того чего хочу, но не разу не писал подобного, как реализовать подобное хранение потоков и обращение к ним???
PM MAIL ICQ Skype   Вверх
mrbrooks
Дата 11.1.2010, 12:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

Репутация: 7
Всего: 306



STRELOKBMSTU, посмотри в сторону класса ThreadPool камрад.

Добавлено через 1 минуту и 1 секунду
подробнее
PM MAIL   Вверх
STRELOKBMSTU
Дата 11.1.2010, 12:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 11.8.2007
Где: Russia.MR.Moscow( );

Репутация: нет
Всего: нет



Посмотрел ThreadPool, возможно он и подойдет, если увеличить максимальное число потоков, но мой вопрос скорее по организации регистрации и разрегистрации пользователей, т.е. как по ключу определить в каком именно потоке висит мой пользователь? и как в случае необходимости разрегистрировать пользователя на сервере опять же по ключу?
PM MAIL ICQ Skype   Вверх
STRELOKBMSTU
Дата 11.1.2010, 13:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 11.8.2007
Где: Russia.MR.Moscow( );

Репутация: нет
Всего: нет



Разобрался с пулом, мне нужен  не пул а обычный запуск каждого сокета в отдельном потоке, но как это все должно храниться, пока не ясно...
PM MAIL ICQ Skype   Вверх
STRELOKBMSTU
Дата 11.1.2010, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 11.8.2007
Где: Russia.MR.Moscow( );

Репутация: нет
Всего: нет



Можно ли создать как-нибудь список потоков?
PM MAIL ICQ Skype   Вверх
mrbrooks
Дата 11.1.2010, 13:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

Репутация: 7
Всего: 306



Цитата(STRELOKBMSTU @  11.1.2010,  13:36 Найти цитируемый пост)
Можно ли создать как-нибудь список потоков? 

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

Добавлено через 4 минуты и 27 секунд
но честно говоря теряюсь в догадках чем не подходит тот же ThreadPool.QueueUserWorkItem. 

PM MAIL   Вверх
STRELOKBMSTU
Дата 11.1.2010, 14:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 11.8.2007
Где: Russia.MR.Moscow( );

Репутация: нет
Всего: нет



Да я все никак не могу разобраться на каком этапе создавать новый поток, у меня слушается порт, соответственно сокет создается внутри самого сервиса а не в новом потоке... а чтобы он создавался в новом потоке, надо и слушать порт в отдельном потоке. Как организовать несколько висящих в памяти сокетов с регистрацией и разрегистрацией их? Вот немного текущего кода:

Код

        private void DoService()
        {
            _isAlive = true;
            
            MemoryStream stream = null;
            byte[] buffer;
            int length = 0;

            _workStarted.Set();

                                     
                try
                {
                    while (_isAlive)
                    {

                        _socket = _listener.AcceptSocket();


                        while (_socket.Connected && (_socket.Available > 0))
                        {
                           buffer = new byte[65535];
                           length = _socket.Receive(buffer);

                           if (length > 0)
                           {
                               stream = new MemoryStream(buffer);
                               XmlSerializer serializer = new XmlSerializer(typeof(MessageObject));
                               MessageObject messageObject = (MessageObject)serializer.Deserialize(stream);

                               if (messageObject != null)
                               {
                                   switch (messageObject.MessageType)
                                   {
                                       case MessageObject.Type.InputMessage:

                                           SendUserMessages(messageObject);
                                           break;

                                       case MessageObject.Type.Register:

                                           UserRegister(messageObject);
                                           break;

                                       case MessageObject.Type.Unregister:

                                           UserUnRegister(messageObject);
                                           break;
                                   }
                               }


                           }
                           else throw new SocketException();

                           _socket.Disconnect(false);
                        }

                       // Thread.Sleep(5);
                    }

                    _workStopped.Set();


                }        
                catch (SocketException e)
                {

                }

                if (_socket != null)
                {
                    _socket.Shutdown(SocketShutdown.Both);
                    _socket.Close();
                    _socket = null;
                }

              _workStopped.Set();

            }

PM MAIL ICQ Skype   Вверх
PashaPash
Дата 11.1.2010, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



STRELOKBMSTU, посмотри msdn по TcpListener.BeginAcceptSocket


--------------------
PM MAIL WWW   Вверх
STRELOKBMSTU
Дата 11.1.2010, 15:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 11.8.2007
Где: Russia.MR.Moscow( );

Репутация: нет
Всего: нет



PashaPash, пасиб, интересная вещь, сейчас ознакомлюсь...

Это сообщение отредактировал(а) STRELOKBMSTU - 11.1.2010, 15:16
PM MAIL ICQ Skype   Вверх
STRELOKBMSTU
Дата 11.1.2010, 15:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 11.8.2007
Где: Russia.MR.Moscow( );

Репутация: нет
Всего: нет



все равно какая-то мутная картина в голове... ведь этот метод выполняется в том же потоке, в котором и был бызван, т.е. многопоточность не получается...
PM MAIL ICQ Skype   Вверх
mrbrooks
Дата 11.1.2010, 16:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

Репутация: 7
Всего: 306



да это обыкновенная асинхронная операция ожидающая входящее подключение. вообще кстати тов. Joseph Albahari советует использовать асинхронные методы в крайних случаях - заменив их использованием асинхронными делегатами. но это к слову.

я так понимаю работа идет с сервером. вообще классическая модель для сервера это использовать потоки + семафоры. 
PM MAIL   Вверх
tol05
Дата 11.1.2010, 17:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



Цитата(PashaPash @  11.1.2010,  13:45 Найти цитируемый пост)
STRELOKBMSTU, посмотри msdn по TcpListener.BeginAcceptSocket 

Так называемая асинхронная модель программирования (Asynchronous Programming Model)

В двух словах - есть рабочие потоки (Thread-ы, как мы привыкли их понимать) и потоки ввода-вывода (они еще называются потоками завершения)
В стримах когда мы используем методы BeginХХХХ - мы активно используем потоки ввода\вывода, перекладывая тем самым часть нагрузки с процессора на драйвер устройства

Об этом хорошо написал Рихтер в своей книге "CLR via C#". В главе о асинхронных операциях. Приведу две цитаты
Цитата

В пуле различают два типа потоков: рабочие потоки и потоки ввода-вывода. 
Первые используются, когда приложение запрашивает пул выполнить  асинхронную вычислительную операцию (которая может включать инициацию операции ввода-вывода). А потоки ввода-вывода служат для уведомления кода о завершении асинхронной операции ввода-вывода. Это значит, что для выполнения запросов, например обращения к файлу, сетевому серверу, базе данных, Web-службе или  
аппаратному устройству, используется модель АРМ (Asynchronous Programming Model). 

О FileStream
Цитата

Вызов метода BeginRead дает Windows команду прочесть байты из файла в байтовый массив. Поскольку это операция ввода-вывода, метод BeginRead ставит этот запрос в очередь драйвера соответствующего аппаратного устройства. Вся работа ложится на аппаратное устройство, и потокам больше ничего не нужно делать — даже ждать результатов операции. Это очень эффективно! 


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


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
PashaPash
Дата 11.1.2010, 17:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



Цитата(STRELOKBMSTU @  11.1.2010,  15:35 Найти цитируемый пост)
все равно какая-то мутная картина в голове... ведь этот метод выполняется в том же потоке, в котором и был бызван, т.е. многопоточность не получается... 

BeginAcceptSocket возвращает управление сразу после вызова. После подключения клиента вызывается Сallback, в отдельном потоке из пула. Т.е. каждому клиенту - свой поток. Все получается.
Цитата(mrbrooks @  11.1.2010,  16:21 Найти цитируемый пост)
вообще кстати тов. Joseph Albahari советует использовать асинхронные методы в крайних случаях - заменив их использованием асинхронными делегатами.

И чем он это мотивирует? smile Внутри Begin/EndXXX - те же асинхронные делегаты. Никаких плюсов от ручного оборачивания BeginAcceptSocket в делегат, и вызова BeginInvoke быть не должно. 


--------------------
PM MAIL WWW   Вверх
STRELOKBMSTU
Дата 11.1.2010, 17:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 11.8.2007
Где: Russia.MR.Moscow( );

Репутация: нет
Всего: нет



Т.е. если одновременно придет много запросов от клиентов, они все встанут в очередь на CallBack или будут выполняться параллельно?

Да, и на BeginAcceptSocket цикл не зависает и не ждет события прихода сокета, а выполняется бесконечно, процесс конечно не сильно нагружается, но что-то не нравится этот бесконечный цикл:

Код

                    while (_isAlive)
                    {

                        _listener.BeginAcceptSocket(new AsyncCallback(DoAcceptSocketCallback), _listener);

                        clientConnected.WaitOne();

                       // Thread.Sleep(5);
                    }


Код

        public void DoAcceptSocketCallback(IAsyncResult ar)
        {
            MemoryStream stream = null;
            byte[] buffer;
            int length = 0;

            TcpListener listener = (TcpListener)ar.AsyncState;

            Socket clientSocket = listener.EndAcceptSocket(ar);

            if (clientSocket.Connected && (clientSocket.Available > 0))
            {
                buffer = new byte[65535];
                length = clientSocket.Receive(buffer);

                if (length > 0)
                {
                    stream = new MemoryStream(buffer);
                    XmlSerializer serializer = new XmlSerializer(typeof(MessageObject));
                    MessageObject messageObject = (MessageObject)serializer.Deserialize(stream);

                    if (messageObject != null)
                    {
                        switch (messageObject.MessageType)
                        {
                            case MessageObject.Type.InputMessage:

                                AddUserMessage(messageObject);
                                break;

                            case MessageObject.Type.Register:

                                UserRegister(messageObject);
                                break;

                            case MessageObject.Type.Unregister:

                                UserUnRegister(messageObject);
                                break;
                        }
                    }


                }
                else throw new SocketException();

            }

            
            clientConnected.Set();
        }


Это сообщение отредактировал(а) STRELOKBMSTU - 11.1.2010, 18:31
PM MAIL ICQ Skype   Вверх
PashaPash
Дата 11.1.2010, 19:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



Цитата(STRELOKBMSTU @  11.1.2010,  17:50 Найти цитируемый пост)
Т.е. если одновременно придет много запросов от клиентов, они все встанут в очередь на CallBack или будут выполняться параллельно?

Параллельно, на потоках из пула.

Цитата(STRELOKBMSTU @  11.1.2010,  17:50 Найти цитируемый пост)

Да, и на BeginAcceptSocket цикл не зависает и не ждет события прихода сокета, а выполняется бесконечно, процесс конечно не сильно нагружается, но что-то не нравится этот бесконечный цикл:

Используй семафор для ограничения на количество одновременно висящих BeginAcceptSocket. Или используй синхронный AcceptSocket, но вынеси обработку в отдельный поток. У того же Joseph Albahari есть пример: http://www.albahari.com/nutshell/ch20.aspx


--------------------
PM MAIL WWW   Вверх
mrbrooks
Дата 12.1.2010, 09:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

Репутация: 7
Всего: 306



Цитата(PashaPash @  11.1.2010,  17:44 Найти цитируемый пост)
И чем он это мотивирует? smile Внутри Begin/EndXXX - те же асинхронные делегаты. Никаких плюсов от ручного оборачивания BeginAcceptSocket в делегат, и вызова BeginInvoke быть не должно.  

Он как бэ советует вызвать синхронную версию метода через асинхронный делегат. Однако рьяно не настаивает.
PM MAIL   Вверх
STRELOKBMSTU
Дата 13.1.2010, 13:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 11.8.2007
Где: Russia.MR.Moscow( );

Репутация: нет
Всего: нет



по BeginAcceptSocket у нас одновременно запускается несколько слушалок, ошидающих подключения сокета, так? Тогда почему не работает WaitOne здесь:

Код


                    while (_isAlive)
                    {
                        _listener.BeginAcceptSocket(new AsyncCallback(DoAcceptSocketCallback), _listener);

                        clientConnected.WaitOne();

                       // Thread.Sleep(5);
                    }


Ведь WaitOne по идее должен заблокировать текущий цикл до тех пор пока в DoAcceptSocketCallback не будет вызван clientConnected.Set(), разве не так???

И в семафоре если делаю так:

Код

private static Semaphore _pool = new Semaphore(0, 25);


Код

                    while (_isAlive)
                    {
                        _listener.BeginAcceptSocket(new AsyncCallback(DoAcceptSocketCallback), _listener);
                     }



Код

        public void DoAcceptSocketCallback(IAsyncResult ar)
        {
            _pool.WaitOne();

            MemoryStream stream = null;
            byte[] buffer;
            int length = 0;

            TcpListener listener = (TcpListener)ar.AsyncState;

            Socket clientSocket = listener.EndAcceptSocket(ar);

            if (clientSocket.Connected && (clientSocket.Available > 0))
            {
                buffer = new byte[65535];
                length = clientSocket.Receive(buffer);

                if (length > 0)
                {
                    stream = new MemoryStream(buffer);
                    XmlSerializer serializer = new XmlSerializer(typeof(MessageObject));
                    MessageObject messageObject = (MessageObject)serializer.Deserialize(stream);

                    if (messageObject != null)
                    {
                        switch (messageObject.MessageType)
                        {
                            case MessageObject.Type.InputMessage:

                                AddUserMessage(messageObject);
                                break;

                            case MessageObject.Type.Register:

                                UserRegister(messageObject);
                                break;

                            case MessageObject.Type.Unregister:

                                UserUnRegister(messageObject);
                                break;
                        }
                    }


                }
                else throw new SocketException();

            }

            
          
            _pool.Release();

        }


цикл бегает бесконечно, т.е. слушалки постоянно создаются? как в этом случае отрабатывает строчка

Код

 _pool.WaitOne();

                   
PM MAIL ICQ Skype   Вверх
STRELOKBMSTU
Дата 13.1.2010, 15:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 11.8.2007
Где: Russia.MR.Moscow( );

Репутация: нет
Всего: нет



Код

_listener.BeginAcceptSocket(new AsyncCallback(DoAcceptSocketCallback), _listener);


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

 и что интересно, то что цикл 

Код

                    while (_isAlive)
                    {
                        
                        _listener.BeginAcceptSocket(new AsyncCallback(DoAcceptSocketCallback), _listener);

                    }


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

Это сообщение отредактировал(а) STRELOKBMSTU - 13.1.2010, 15:21
PM MAIL ICQ Skype   Вверх
PashaPash
Дата 13.1.2010, 17:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



clientConnected - это ManualReset или AutoReset Event?
А семафор надо немного по другому юзать - ждать перед BeginAcceptSocket, освобождать в начале DoAcceptSocketCallback.


--------------------
PM MAIL WWW   Вверх
WolfTheGrey
Дата 23.1.2010, 05:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 207
Регистрация: 21.1.2009
Где: forum.vingrad.ru

Репутация: нет
Всего: 2



А зачем вы вызываете Thread.Sleep() Он не усыпляет поток, а откладывает его в очередь потоков на определенное время. И то не факт, что поток возобновит свою работу именно через этот промежуток времени.

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

И вернемся к теме:
сервер: имеет структуру с данными о клиенте. Копии структур (клиентов) хранятся в масве. Хранить в структуе можно все, даже его IP адрес.

при подключении клиента TcpClient client=listener.AseptTcpClient();

ты уже знаешь его IP и ищеш в базе его данные по его IP.

Можешь дождаться когда клиент пришлет свой пароль :

string pass=client.Read();


И вернемся к многопоточности:

Методы- Read(); и AseptTcpClient() - создают новый поток. (так мне компилятор сказал - когда я расматривал создаваемые потоки в процессе работы програмы)

PM MAIL   Вверх
PashaPash
Дата 23.1.2010, 13:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



Цитата(WolfTheGrey @  23.1.2010,  05:21 Найти цитируемый пост)
А зачем вы вызываете Thread.Sleep() Он не усыпляет поток, а откладывает его в очередь потоков на определенное время. И то не факт, что поток возобновит свою работу именно через этот промежуток времени.

А зачем ты написал этот кусок текста? Thread.Sleep там закомменчен.

Цитата(WolfTheGrey @  23.1.2010,  05:21 Найти цитируемый пост)
Отведь себе на вопрос: сколько клиентов ты собераешся одновременно обробатывать?
и нужен ли тебе весь этот Многпоточный хлам?

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

Цитата(WolfTheGrey @  23.1.2010,  05:21 Найти цитируемый пост)
И вернемся к теме:
сервер: имеет структуру с данными о клиенте. Копии структур (клиентов) хранятся в масве. Хранить в структуе можно все, даже его IP адрес.

при подключении клиента TcpClient client=listener.AseptTcpClient();

ты уже знаешь его IP и ищеш в базе его данные по его IP.

Можешь дождаться когда клиент пришлет свой пароль :

string pass=client.Read();

В теме не упоминалось что вообще есть какая-то база данных. Перечитай первое сообщение - там подразумевалось хранить инфу о подключенных в данный момент пользователях. Странно при подключении искать там "его IP".
Про пароль тоже неожиданно smile Какое еще пароль?
Цитата(WolfTheGrey @  23.1.2010,  05:21 Найти цитируемый пост)
И вернемся к многопоточности:

Методы- Read(); и AseptTcpClient() - создают новый поток. (так мне компилятор сказал - когда я расматривал создаваемые потоки в процессе работы програмы)

Компилятор, в процессе работы? хм... а у меня отладчик говорит что AcceptTcpClient не создает поток. И что какой-то выбранный наугад StreamReader.Read - тоже не создает. Мой отладчик сильнее твоего компилятора! smile



--------------------
PM MAIL WWW   Вверх
WolfTheGrey
Дата 24.1.2010, 03:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 207
Регистрация: 21.1.2009
Где: forum.vingrad.ru

Репутация: нет
Всего: 2



Цитата
А зачем ты написал этот кусок текста? Thread.Sleep там закомменчен.
 -это писал нея, это писал: "Джеффери Рихтер" CLR VIA C#.

Цитата
Разработчики - ленивые существа
 - не обобщай!

Цитата
там подразумевалось хранить инфу о подключенных в данный момент пользователях
 - так храни! а как пользователь отключится так удаляй из списка. (под фразой "база данных" я имел в виду List<T> и процесс сохранения)

Цитата
а у меня отладчик говорит что AcceptTcpClient не создает поток
 - не знание законов не освобождает от отыетственности. Переведу: 


smile

Это сообщение отредактировал(а) WolfTheGrey - 24.1.2010, 03:04
PM MAIL   Вверх
PashaPash
Дата 24.1.2010, 04:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



Цитата(WolfTheGrey @  24.1.2010,  03:02 Найти цитируемый пост)
-это писал нея, это писал: "Джеффери Рихтер" CLR VIA C#.

Ок, может быть не дошло, объясню по другому - в этом топике нет ни одного вызова Thread.Sleep. Рихтер наверняка писал и про другие функции, не имеющие отношения к этому топику, не стоит копипастить сюда всю книгу.

Цитата(WolfTheGrey @  24.1.2010,  03:02 Найти цитируемый пост)

 - так храни! а как пользователь отключится так удаляй из списка. (под фразой "база данных" я имел в виду List<T> и процесс сохранения)

Ок, еще раз:
1. В списке держим подключенных пользователей
2. При отключении - удаляем
3. При подключении - ищем в списке по IP
4. И гарантировано не находим...


--------------------
PM MAIL WWW   Вверх
uranpro
Дата 24.1.2010, 13:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 571
Регистрация: 7.5.2008
Где: Moscow city

Репутация: 1
Всего: 1



можно мне плюсик за пост =)
мой сервер, до 4к подключений
Код

    public delegate void AddResultDelegate(string Msg);
    public delegate void GetDataDelegate(byte[] Data, int Length, Socket Client);

    public class SocketServer
    {

        public int BufferSize { get; private set; }

        AddResultDelegate AddResult { get; set; }

        void _AddResult(string Msg)
        {
            if (AddResult != null)
                AddResult("Server: " + Msg);
        }

        GetDataDelegate GetData { get; set; }

        void _GetData(byte[] Data, int Length, Socket Client)
        {
            if (GetData != null)
                GetData(Data, Length, Client);
        }

        Socket Server { get; set; }

        public int Port { get; private set; }

        const int ThreadCount = 10;

        class ConnectionInfo
        {
            public Socket Client;
            public byte[] Buffer;
        }

        List<ConnectionInfo> Connections = new List<ConnectionInfo>();

        public SocketServer(int Port, int BufferSize, AddResultDelegate AddResult, GetDataDelegate GetData)
        {
            this.Port = Port;
            this.BufferSize = BufferSize;
            this.AddResult = AddResult;
            this.GetData = GetData;
        }

        public void Start()
        {
            SetupSocketServer();
            for (int i = 0; i < ThreadCount; i++)
                Server.BeginAccept(new AsyncCallback(AcceptCallBack), Server);
        }

        void AcceptCallBack(IAsyncResult iar)
        {
            var Connection = new ConnectionInfo();
            try
            {
                var s = (Socket)iar.AsyncState;
                Connection.Client = s.EndAccept(iar);
                Connection.Buffer = new byte[BufferSize];
                lock (Connections) Connections.Add(Connection);

                Connection.Client.BeginReceive(Connection.Buffer,
                    0,
                    Connection.Buffer.Length,
                    SocketFlags.None,
                    new AsyncCallback(ReceiverCallBack),
                    Connection);

                Server.BeginAccept(new AsyncCallback(AcceptCallBack), iar.AsyncState);

                _AddResult("Client " + Connection.Client.RemoteEndPoint.ToString() + " connected");
            }
            catch (SocketException ex)
            {
                CloseConnection(Connection);
                _AddResult("SocketException: " + ex.Message);
            }
            catch (Exception ex)
            {
                CloseConnection(Connection);
                _AddResult("Exception: " + ex.Message);
            }
        }

        void ReceiverCallBack(IAsyncResult iar)
        {
            ConnectionInfo Connection = (ConnectionInfo)iar.AsyncState;
            try
            {
                int recv = Connection.Client.EndReceive(iar);
                if (recv != 0)
                {
                    //

                    _AddResult("Client " + Connection.Client.RemoteEndPoint.ToString() +
                        " : " + "recvLength: " + recv.ToString());
                    _GetData(Connection.Buffer, recv, Connection.Client);

                    Connection.Client.BeginReceive(Connection.Buffer,
                        0,
                        Connection.Buffer.Length,
                        SocketFlags.None,
                        new AsyncCallback(ReceiverCallBack),
                        Connection);
                }
                else
                    CloseConnection(Connection);
            }
            catch (SocketException ex)
            {
                CloseConnection(Connection);
                _AddResult("SocketException: " + ex.Message);
            }
            catch (Exception ex)
            {
                CloseConnection(Connection);
                _AddResult("Exception: " + ex.Message);
            }
        }

        void SetupSocketServer()
        {

            var info = Dns.GetHostEntry(Dns.GetHostName());
            var ip = new IPEndPoint(info.AddressList[0], Port);

            try
            {
                Server = new Socket(ip.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                Server.ReceiveBufferSize = BufferSize;
                Server.SendBufferSize = BufferSize;
                Server.Bind(ip);
                Server.Listen((int)SocketOptionName.MaxConnections);
                _AddResult("Listening for connections");
            }
            catch (SocketException ex)
            {
                _AddResult("SocketException: " + ex.Message);
            }
            catch (Exception ex)
            {
                _AddResult("Exception: " + ex.Message);
            }
        }

        void CloseConnection(ConnectionInfo Connection)
        {
            try
            {
                _AddResult("Client " + Connection.Client.RemoteEndPoint.ToString() + " disconnected");
                Connection.Client.Close();
            }
            catch (Exception ex)
            {
                _AddResult("Exception: " + ex.Message);
            }
            lock (Connections) Connections.Remove(Connection);
        }

    }

используй BinaryFormatter !!! гораздо быстрее и меньше весит.


--------------------
I want a perfect soul
PM MAIL ICQ   Вверх
PashaPash
Дата 24.1.2010, 16:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



uranpro, мелкий баг - чисто теоретически, после 10 ошибок между try и BeginAccept в AcceptCallBack сервер перестанет аццептить вообще ;)


--------------------
PM MAIL WWW   Вверх
uranpro
Дата 24.1.2010, 16:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 571
Регистрация: 7.5.2008
Где: Moscow city

Репутация: 1
Всего: 1



PashaPash, ага, спасибо, исправим =)

Добавлено через 3 минуты и 43 секунды
Код

        void AcceptCallBack(IAsyncResult iar)
        {
            var Connection = new ConnectionInfo();
            try
            {
                var s = (Socket)iar.AsyncState;
                Connection.Client = s.EndAccept(iar);
                Connection.Buffer = new byte[BufferSize];
                lock (Connections) Connections.Add(Connection);

                Connection.Client.BeginReceive(Connection.Buffer,
                    0,
                    Connection.Buffer.Length,
                    SocketFlags.None,
                    new AsyncCallback(ReceiverCallBack),
                    Connection);

                _AddResult("Client " + Connection.Client.RemoteEndPoint.ToString() + " connected");
            }
            catch (SocketException ex)
            {
                CloseConnection(Connection);
                _AddResult("SocketException: " + ex.Message);
            }
            catch (Exception ex)
            {
                CloseConnection(Connection);
                _AddResult("Exception: " + ex.Message);
            }
            finally
            {
                Server.BeginAccept(new AsyncCallback(AcceptCallBack), iar.AsyncState);
            }
        }



--------------------
I want a perfect soul
PM MAIL ICQ   Вверх
WolfTheGrey
Дата 25.1.2010, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 207
Регистрация: 21.1.2009
Где: forum.vingrad.ru

Репутация: нет
Всего: 2



uranpro
Понравился код, и от меня ему плюсик поставьте!

Только я одного не понял, в каком месте происходит массовая рассылка? (тоесть один сказал - все услышали).
Если это не предусмотренно, то нужно как то истправлять положение! smile
PM MAIL   Вверх
uranpro
Дата 25.1.2010, 16:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 571
Регистрация: 7.5.2008
Где: Moscow city

Репутация: 1
Всего: 1



WolfTheGrey, а это уже другой класс =) у меня. вставь в делегат GetData Connections и все, делов минута =)
тело делегата
Код

            lock (Connections)
                foreach (var Client in Connections)
                    Client.Client.Send(Data);



--------------------
I want a perfect soul
PM MAIL ICQ   Вверх
WolfTheGrey
Дата 26.1.2010, 05:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 207
Регистрация: 21.1.2009
Где: forum.vingrad.ru

Репутация: нет
Всего: 2



uranpro, я так умею, а вот на асинхронных операциях бы!
PM MAIL   Вверх
uranpro
Дата 26.1.2010, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 571
Регистрация: 7.5.2008
Где: Moscow city

Репутация: 1
Всего: 1



вот, без разницы, асинхронная модель или нет
Код

        void ReceiverCallBack(IAsyncResult iar)
        {
            ConnectionInfo Connection = (ConnectionInfo)iar.AsyncState;
            try
            {
                int recv = Connection.Client.EndReceive(iar);
                if (recv != 0)
                {
                    //

                    lock (Connections)
                        foreach (ConnectionInfo ci in Connections)
                            if (ci != Connection)
                                ci.Client.Send(Connection.Buffer);


                    _AddResult("Client " + Connection.Client.RemoteEndPoint.ToString() +
                        " : " + "recvLength: " + recv.ToString());
                    _GetData(Connection.Buffer, recv, Connection.Client);

                    Connection.Client.BeginReceive(Connection.Buffer,
                        0,
                        Connection.Buffer.Length,
                        SocketFlags.None,
                        new AsyncCallback(ReceiverCallBack),
                        Connection);
                }
                else
                    CloseConnection(Connection);
            }
            catch (SocketException ex)
            {
                CloseConnection(Connection);
                _AddResult("SocketException: " + ex.Message);
            }
            catch (Exception ex)
            {
                CloseConnection(Connection);
                _AddResult("Exception: " + ex.Message);
            }
        }



--------------------
I want a perfect soul
PM MAIL ICQ   Вверх
WolfTheGrey
Дата 27.1.2010, 01:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 207
Регистрация: 21.1.2009
Где: forum.vingrad.ru

Репутация: нет
Всего: 2



А как проверить сколько клиентов вытянит сервер? (учитывая что комп один )




PM MAIL   Вверх
Страницы: (3) [Все] 1 2 3 
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1431 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.