Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> При создании второго потока, первый отключается. многопоточный сервер, проблема 
V
    Опции темы
fiss
Дата 26.1.2009, 17:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Здравствуйте, начал писать многопоточный сервер.
Вот код:
Код

#include <iostream>
#include "sockets.h"
#include <process.h>
using namespace std;

Socket sock;

const int N = 40;
unsigned int id[N];    
HANDLE hThread[N];

unsigned __stdcall ClientThread( void* dummy );

int main()
{
    sock.Bind( 7495 );
    sock.Listen();

    for(int i=0; i<N; i++)
    {
        hThread[i] = (HANDLE)_beginthreadex( NULL, 0, &ClientThread, (void*)i, 0, &id[i] );
        Sleep(100);
    }

    Sleep(INFINITE);

    return 0;
}

unsigned __stdcall ClientThread( void *dummy )
{
    sock.Accept();
    cout << "ClientThread started.\n";
    
    for(;;)
    {
        char recvBuf[STRLEN];
        sock.RecvData(recvBuf, STRLEN);
        cout << recvBuf << "\n";
    }
}

sockets.h - хеадер от класса для работы с сокетами.

Необходимо чтобы сообщения со всех подключенных клиентов отображались в консоли на сервере.

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

p.s. Код функций работы с сокетами:
Код

void Socket::Accept()
{    
    acceptSocket = accept( fiSocket, NULL, NULL );
    if( acceptSocket == SOCKET_ERROR )
    {
        cout << "Socket: Accept error.\n";
    }
    else
    {
        cout << "Socket: accept successfull.\n";
    }
}

bool Socket::SendData( char *buffer )
{
    send( acceptSocket, buffer, STRLEN, 0 );
    return true;
}

bool Socket::RecvData( char *buffer, int size )
{
    int i = recv( acceptSocket, buffer, size, 0 );
    buffer[i] = '\0';
    return true;
}

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


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

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



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

но это не критично, критично то, что все потоки после обработки своего сокета закрываются, а новые - не создаются, следовательно, сервер становится недееспособным, отсюда и проблема

нужно в потоках сменить организацию приема клиентов в цикл
и перед чтением сообщения с клиента, проверять буфер на пустоту, т.е. добавлять еще один recv с флагом PEEK

Это сообщение отредактировал(а) GremlinProg - 26.1.2009, 22:40


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
xvr
Дата 27.1.2009, 13:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



Твой класс Socket не расчитан на многопоточную работу - метод Accept переписывает переменную acceptSocket, которая получается единственной на ВСЕ нити сервера. Соотвественно работать будет только последняя нить, которая сделала Accept
 
PM MAIL   Вверх
fiss
Дата 27.1.2009, 16:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Спасибо всем! Заработало, дело было в acceptSocket (смотреть пост xvr).

Вот работающий код:

Код

#include <iostream>
#include "sockets.h"
#include <process.h>
using namespace std;

Socket sock;
const int N = 40;
unsigned int id[N];    
HANDLE hThread[N];

unsigned __stdcall ClientThread( void* dummy );

int main()
{
    sock.Bind( 7495 );
    sock.Listen();

    for(int i = 0; i < N; i++ )
    {
        hThread[i] = (HANDLE)_beginthreadex( NULL, 0, &ClientThread, (void *)i, 0, &id[i] );
        Sleep(1000);
    }

    Sleep(1000);

    return 0;
}

unsigned __stdcall ClientThread( void *dummy )
{
    int i = (int)dummy;
    sock.Accept(i);

    cout << "ClientThread started ID: " << i << "\n";
    
    while(true)
    {
        char recvBuf[STRLEN];
        sock.RecvData(recvBuf, STRLEN, i);
        cout << recvBuf << "\n";

        Sleep(1000);
    }
}


И код функций:

Код

bool Socket::SendData( char *buffer, int i )
{
    send( acceptSocket[i], buffer, STRLEN, 0 );
    return true;
}

bool Socket::RecvData( char *buffer, int size, int i )
{
    int m = recv( acceptSocket[i], buffer, size, 0 );
    buffer[m] = '\0';
    return true;
}

void Socket::Accept( int i )
{    
    acceptSocket[i] = accept( fiSocket, NULL, NULL );
    if( acceptSocket[i] == SOCKET_ERROR )
    {
        cout << "Socket: Accept error.\n";
    }
    else
    {
        cout << "Socket: accept connection ID: " << i << ".\n";
    }
}

PM MAIL ICQ MSN   Вверх
fiss
Дата 27.1.2009, 20:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



p.s. извиняюсь за то что создал еще один пост (мне его просто не удалить), вот работающий без багов код (в предыдущем посте сервер обрубался по истечению некоторого времени).
Код

#include <iostream>
#include "sockets.h"
#include <process.h>
using namespace std;

Socket sock;
const int N = 40;
unsigned int id[N];    
HANDLE hThread[N];

unsigned __stdcall ClientThread( void* dummy );

void main()
{
    sock.Bind( 7495 );
    sock.Listen();

    for(int i = 0; i < N; i++ )
    {
        hThread[i] = (HANDLE)_beginthreadex( NULL, 0, &ClientThread, (void *)i, 0, &id[i] );
        Sleep(1000);
    }

    Sleep(INFINITE);
}


unsigned __stdcall ClientThread( void *dummy )
{
    int i = (int)dummy;
    sock.Accept(i);

    cout << "ClientThread started ID: " << i << "\n";
    
    for(;;)
    {
        char recvBuf[STRLEN];
        sock.RecvData(recvBuf, STRLEN, i);
        cout << recvBuf << "\n";

        Sleep(1000);
    }
}


Это сообщение отредактировал(а) fiss - 27.1.2009, 20:48
PM MAIL ICQ MSN   Вверх
xvr
Дата 27.1.2009, 23:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



Я бы разделил класс Socket на 2 - слушающий сервер и собственно рабочий экземпляр. accept должен делать второй класс в своем конструкторе

PM MAIL   Вверх
GremlinProg
Дата 28.1.2009, 00:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

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



fiss, поставь N = 2 и пошли серверу с 3-х разных к нему соединений по одному сообщению


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
fiss
Дата 28.1.2009, 15:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(GremlinProg @  28.1.2009,  00:36 Найти цитируемый пост)
fiss, поставь N = 2 и пошли серверу с 3-х разных к нему соединений по одному сообщению 

Дак это понятно. третий не примется. Это же не законченная версия сервера, меня просто интересовала проблема потоков и accept smile. 



Это сообщение отредактировал(а) fiss - 28.1.2009, 15:19
PM MAIL ICQ MSN   Вверх
GoldFinch
Дата 28.1.2009, 18:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


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

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



я бы не юзал ооп там где это не надо
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




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


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

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