powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Самый простой многопоточный сервер на именованных каналах, пара вопросов
9 сообщений из 9, страница 1 из 1
Самый простой многопоточный сервер на именованных каналах, пара вопросов
    #38604489
mr_virtus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравсвуйте,

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

Вот основной код на сервере:

Код: plaintext
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.
void MainWindow::on_Run_clicked()
{
    DWORD iNp;
    int MAX_CLIENTS = 20;
    ThreadArg* ThArgs[MAX_CLIENTS];
    HANDLE hT[MAX_CLIENTS];
    for (iNp = 0; iNp < MAX_CLIENTS; iNp++){
        hNp = CreateNamedPipe(PIPE_NAME,
                              PIPE_ACCESS_DUPLEX,
                              PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE | PIPE_WAIT,
                              PIPE_UNLIMITED_INSTANCES,
                              0,
                              0,
                              INFINITE,
                              0);
        if (hNp != INVALID_HANDLE_VALUE){
            MessageBox(0, L"Named pipe is created", L"Info", MB_OK);
        }
        if (ConnectNamedPipe(hNp, 0) == 0){
            MessageBox(0, L"ConnectNamedPipe failed with with error", L"Info", MB_OK);
            CloseHandle(hNp);
        }
        ThArgs[iNp] = new ThreadArg(hNp, iNp);
        hT[iNp] = CreateThread(0, 0, ThreadFunction, ThArgs[iNp], 0, 0);
        QObject::connect(ThArgs[iNp], SIGNAL(needWriteRequest(QString)), this, SLOT(paintRequest(QString)), Qt::BlockingQueuedConnection);

    }
    WaitForMultipleObjects(iNp, hT, TRUE, INFINITE);
    for (int i =0; i < iNp; i++){
        CloseHandle(hT[i]);
        //DisconnectNamedPipe(ThArgs[i]->hNamedPipe);
    }
}

DWORD WINAPI MainWindow::ThreadFunction(LPVOID threadArg){
    ThreadArg* p = static_cast<ThreadArg*>(threadArg);
    DWORD Read;
    DWORD Written;
    char Buf[256];
    char BufWr[256];

    if (ReadFile(p->hNamedPipe, Buf, 256, &Read, 0) <= 0){
        MessageBox(0, L"ReadFile failed with error", L"Info", MB_OK);
        CloseHandle(p->hNamedPipe);
    }
    QString qstr = QString::fromUtf8(Buf);
    emit p->needWriteRequest(qstr);

    QString ans = "answer";
    strcpy(BufWr, ans.toLocal8Bit().data());
    WriteFile(p->hNamedPipe, BufWr, sizeof(BufWr), &Written, 0);
    delete p;
    return 0;
}



Вот основной код на клиенте:

Код: plaintext
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.
void MainWindow::on_CreateConnection_clicked()
{
    if (WaitNamedPipe(PIPE_NAME, NMPWAIT_WAIT_FOREVER) == 0) {
        MessageBox(0, L"WaitNamedPipe failed with error", L"Info", MB_OK);
        return;
    }

    if ((hNp = CreateFile(PIPE_NAME,
                          GENERIC_READ | GENERIC_WRITE, 0,
                          (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING,
                          FILE_ATTRIBUTE_NORMAL,
                          (HANDLE) NULL)) == INVALID_HANDLE_VALUE){
        MessageBox(0, L"CreateFile failed with error", L"Info", MB_OK);
    }

    DWORD Written;
    char BufWr[256];
    QString qstr = "request";
    strcpy(BufWr, qstr.toLocal8Bit().data());
    if (WriteFile(hNp, BufWr, sizeof(BufWr), &Written, NULL) == 0)
    {
        MessageBox(0, L"WriteFile failed with error", L"Info", MB_OK);
        CloseHandle(hNp);
        return;
    }
    DWORD Read;
    char Buf[256];
    if (ReadFile(hNp, Buf, 256, &Read, 0) <= 0){
        MessageBox(0, L"ReadFile failed with error", L"Info", MB_OK);
        CloseHandle(hNp);
        return;
    }
    QString qstrAns = QString::fromUtf8(Buf);
    ui->label->setText(qstrAns);
}



Проблема в том, что обмен сервер зависает в конце. Сообщения посылаются, но сервер подвисает.
И ещё. Мне нужно, чтоб клиент посылал запросы серверу периодически, а не один раз как у меня.
Как это можно исправить?

Спасибо.
...
Рейтинг: 0 / 0
Самый простой многопоточный сервер на именованных каналах, пара вопросов
    #38604508
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то в коде делается CloseHandle а потом в этот же закрытый хендл делается WriteFile.
...
Рейтинг: 0 / 0
Самый простой многопоточный сервер на именованных каналах, пара вопросов
    #38604518
smald
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
[quot mr_virtus]

Извиняюсь, что не по делу, просто интересно на каком курсе учитесь?

А, если по делу, то что у Вас thread функция не зациклена?
...
Рейтинг: 0 / 0
Самый простой многопоточный сервер на именованных каналах, пара вопросов
    #38604522
mr_virtus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

авторГде-то в коде делается CloseHandle а потом в этот же закрытый хендл делается WriteFile.

Код: plaintext
1.
2.
3.
4.
5.
WaitForMultipleObjects(iNp, hT, TRUE, INFINITE);
    for (int i =0; i < iNp; i++){
        CloseHandle(hT[i]);
        //DisconnectNamedPipe(ThArgs[i]->hNamedPipe);
    }



Вот здесь я комментил, но результат не дало. А в другие CloseHandle я не попадаю. Или я что-тоне понимаю?=)
...
Рейтинг: 0 / 0
Самый простой многопоточный сервер на именованных каналах, пара вопросов
    #38604528
mr_virtus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
smald,

авторИзвиняюсь, что не по делу, просто интересно на каком курсе учитесь?

Предпоследний. С какой целью интересуетесь?

авторА, если по делу, то что у Вас thread функция не зациклена?

Ну да, я тоже об этом подумал. Что по идее, если нужно несколько раз слать сообщения, то нужно писать цикл. Как в нем только задать условие выхода?
...
Рейтинг: 0 / 0
Самый простой многопоточный сервер на именованных каналах, пара вопросов
    #38604562
smald
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mr_virtus
Ну да, я тоже об этом подумал. Что по идее, если нужно несколько раз слать сообщения, то нужно писать цикл. Как в нем только задать условие выхода?

Цикл должен быть в thread функции, а то у Вас сервак в отдельном
потоке слушает, читает, делает write, и умирает.
И цикл в клиенте. Выход хоть через регистрацию обработчика POSIX сигнала, хоть отслеживание
действий пользователя в GUI. Да море возможностей, какой-нибудь QtButton повесьте,
и назначьте слотом на сигнал о клике уничтожение процесса.
...
Рейтинг: 0 / 0
Самый простой многопоточный сервер на именованных каналах, пара вопросов
    #38604926
mr_virtus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
Цикл должен быть в thread функции, а то у Вас сервак в отдельном
потоке слушает, читает, делает write, и умирает.
И цикл в клиенте



Ну да. В клиенте точно. Думаю, чтоб периодически отправлять запросы с клиента использовать таймер.

Еще с одной ошибкой разобрался, почему висел сервак:

авторWaitForMultipleObjects(iNp, hT, TRUE, INFINITE);
авторВыход хоть через регистрацию обработчика POSIX сигнала, хоть отслеживание
действий пользователя в GUI.

Не очень понял момент - " через регистрацию обработчика POSIX".? А отслеживать действия пользователя - это, например, при нажатии кнопки - убивается процесс?
...
Рейтинг: 0 / 0
Самый простой многопоточный сервер на именованных каналах, пара вопросов
    #38604936
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mr_virtusВот здесь я комментил, но результат не дало. А в другие CloseHandle я не попадаю. Или я что-тоне понимаю?=)

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
DWORD WINAPI MainWindow::ThreadFunction(LPVOID threadArg){
    ThreadArg* p = static_cast<ThreadArg*>(threadArg);
    DWORD Read;
    DWORD Written;
    char Buf[256];
    char BufWr[256];

    if (ReadFile(p->hNamedPipe, Buf, 256, &Read, 0) <= 0){
        MessageBox(0, L"ReadFile failed with error", L"Info", MB_OK);
        CloseHandle(p->hNamedPipe);
    }
    QString qstr = QString::fromUtf8(Buf);
    emit p->needWriteRequest(qstr);

    QString ans = "answer";
    strcpy(BufWr, ans.toLocal8Bit().data());
    WriteFile(p->hNamedPipe, BufWr, sizeof(BufWr), &Written, 0);
    delete p;
    return 0;
}
...
Рейтинг: 0 / 0
Самый простой многопоточный сервер на именованных каналах, пара вопросов
    #38605075
mr_virtus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

Вот здесь я комментил, но результат не дало. А в другие CloseHandle я не попадаю. Или я что-тоне понимаю?=)


авторDWORD WINAPI MainWindow::ThreadFunction(LPVOID threadArg){
ThreadArg* p = static_cast<ThreadArg*>(threadArg);
DWORD Read;
DWORD Written;
char Buf[256];
char BufWr[256];

if (ReadFile(p->hNamedPipe, Buf, 256, &Read, 0) <= 0){
MessageBox(0, L"ReadFile failed with error", L"Info", MB_OK);
CloseHandle(p->hNamedPipe);
}
QString qstr = QString::fromUtf8(Buf);
emit p->needWriteRequest(qstr);

QString ans = "answer";
strcpy(BufWr, ans.toLocal8Bit().data());
WriteFile(p->hNamedPipe, BufWr, sizeof(BufWr), &Written, 0);
delete p;
return 0;
}

Я думаю дело не в этом. В этот CloseHandle мы попадаем, только если не смогли прочитать байты.

Там проблема была в функции
WaitForMultipleObjects(iNp, hT, TRUE, INFINITE);
Я поставил max_clients = 20;
а сам не запускал столько клиентов, вот сервер и вис.

Теперь осталось дописать код, чтоб клиент переодически отправлял сообщения, а сервер их считывал.
...
Рейтинг: 0 / 0
9 сообщений из 9, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / Самый простой многопоточный сервер на именованных каналах, пара вопросов
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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