Модераторы: feodorv
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Многопоточность+WinSock, Как организовать? клиент+два сервера 
:(
    Опции темы
Toyamatokanava
Дата 28.12.2015, 22:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 62
Регистрация: 29.10.2012
Где: Ростов-на-Дону

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



Как сделать так, чтобы клиент принимал от двух серверов сообщения  в разных потоках?  Собственно я сделал следующее, инициализировал настройки под два сокета с разными портами и одним локальным ip, так как тестирую на одной машине, потом в while(1)  создаю нить и принимаю от одного сокета. Я просто не могу понять как сделать так, чтобы программа понимала с какого порта прием(или сокета). Может я не разобрался в теме конечно, направте пожалуйста.)


Код

// tcp_client.cpp: определяет точку входа для консольного приложения.
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <string.h>
#include <Windows.h>
#include <fstream>
#include <iostream>

using namespace std;
#define SERVERADDR "192.168.1.8"
DWORD WINAPI priem(LPVOID );
#pragma comment(lib,"ws2_32.lib")

int _tmain(int argc, _TCHAR* argv[])
{
    char buff[1024];
    int *port = new int[2];
    //ifstream fin("Config.txt");
    //выделим память под количество портов
    port[0] = 666;
    port[1] = 667;
    memset(buff, '0', 1024);//очищаем наш буфер от мусора
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);

    printf("TCP DEMO CLIENT\n");
    //шаг 1 - инициализация библиотеки Winsock
    if (WSAStartup(0x202, (WSADATA *)&buff[0]))
    {
        printf("WSAStart error %d\n", WSAGetLastError());
        return -1;
    }
    //Шаг 2 - создание сокета

    SOCKET *my_sock = new SOCKET[2];
    for (int i = 0; i < 2; i++)//2 - это количество соединений
    {
        my_sock[i] = socket(AF_INET, SOCK_STREAM, 0);

        if (my_sock[i] < 0)
        {
            printf("Socket() error %d\n", WSAGetLastError());
            return -1;
        }

        //Шаг 3 - установка соединения//для клиента
        //заполнение структуры sockaddr_in
        //указание адреса и порта сервера
        sockaddr_in* dest_addr = new sockaddr_in[2];

        dest_addr[i].sin_family = AF_INET;
        dest_addr[i].sin_port = htons(port[i]);
        HOSTENT **hst = new HOSTENT*[2];
        //преобразование IP адреса из символьного в сетевой формат
        if (inet_addr(SERVERADDR) != INADDR_NONE)
            dest_addr[i].sin_addr.s_addr = inet_addr(SERVERADDR);
        //попытка получить IP адрес по доменному
        //имени сервера
        if (hst[i] = gethostbyname(SERVERADDR))
            //hst->h_addr_list  содержит не массив адресов,
            //а массив указателей на адреса
            ((unsigned long*)&dest_addr[i].sin_addr)[0] = ((unsigned long **)hst[i]->h_addr_list)[0][0];
        else
        {
            printf("Invalid address %s\n", SERVERADDR);
            closesocket(my_sock[i]);
            WSACleanup();
            return -1;
        }



        if (connect(my_sock[i], (sockaddr*)&dest_addr[i], sizeof(dest_addr[i])))
        {
            printf("Connect error %d\n", WSAGetLastError());
            return -1;
        }
    }




    while (1)
    {
        //выводим на экран
        //читаем пользовательский ввод с клавиатуры

        DWORD thID;//
        CreateThread(NULL, NULL, priem, my_sock, NULL, &thID);

        //проверка на "quit"

        //передаем строку клиента серверу
    }
}


DWORD WINAPI priem(LPVOID pmy_sock)
{
    SOCKET * my_sock = (SOCKET *)pmy_sock;
    char buff[1024];
    int recvb=0;
    recvb=recv(my_sock[1], &buff[0], strlen(buff)+1, 0);
    for (int i = 0; i<recvb;i++)
    printf("%c",buff[i]);
    //send(my_sock[0],&buff[0],recvb,0);
    return 0;
    
}




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


Эксперт
****


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

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



Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
Как сделать так, чтобы клиент принимал от двух серверов сообщения  в разных потоках?

Можно сделать и так, чтобы клиент принимал от двух серверов в одном потоке)))


Сначала об ошибках. Вот здесь Вы справедливо вынесли создание массива за пределы цикла:
Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
    SOCKET *my_sock = new SOCKET[2];
А вот здесь почему-то нет:
Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
        sockaddr_in* dest_addr = new sockaddr_in[2];
Вообще, довольно странное увлечение конструкциями типа
Код
xxx *v = new xxx[2];
когда достаточно просто
Код
xxx v[2];
И высвобождать память потом не нужно.


Вот здесь забыто else:
Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
if (inet_addr(SERVERADDR) != INADDR_NONE)
            dest_addr[i].sin_addr.s_addr = inet_addr(SERVERADDR);
        //попытка получить IP адрес по доменному
        //имени сервера
        else if (hst[i] = gethostbyname(SERVERADDR))
            //hst->h_addr_list  содержит не массив адресов,
            //а массив указателей на адреса
            ((unsigned long*)&dest_addr[i].sin_addr)[0] = ((unsigned long **)hst[i]->h_addr_list)[0][0];
        else
        {
            printf("Invalid address %s\n", SERVERADDR);
            closesocket(my_sock[i]);
            WSACleanup();
            return -1;
        }



Почему strlen(buff), да ещё плюс один (он-то откуда взялся), когда нужен sizeof(buff):
Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
    recvb=recv(my_sock[1], &buff[0], strlen(buff)+1sizeof(buff), 0);



Теперь о деле. Зачем отравлять в каждый поток одинаковый аргумент my_sock? Отправляйте соответствующий сокет:
Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
       CreateThread(NULL, NULL, priem, my_sock[ i ], NULL, &thID);
Соответственно, схема с while(1) никуда не годится. Если хотите дождаться выполнения потоков, обратите внимание на возвращаемое вызовом CreateThread значение (а возвращаемый хендл всё равно закрывать нужно, иначе утечка хендлов) и функцию WaitForMultipleObjects().


PS Зря я тему перенёс, она скорее касается WinAPI, чем работы с сокетом...



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Toyamatokanava
Дата 29.12.2015, 18:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 62
Регистрация: 29.10.2012
Где: Ростов-на-Дону

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



Цитата(feodorv @ 29.12.2015,  04:16)
Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
Как сделать так, чтобы клиент принимал от двух серверов сообщения  в разных потоках?

Можно сделать и так, чтобы клиент принимал от двух серверов в одном потоке)))


Сначала об ошибках. Вот здесь Вы справедливо вынесли создание массива за пределы цикла:
Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
    SOCKET *my_sock = new SOCKET[2];
А вот здесь почему-то нет:
Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
        sockaddr_in* dest_addr = new sockaddr_in[2];
Вообще, довольно странное увлечение конструкциями типа
Код
xxx *v = new xxx[2];
когда достаточно просто
Код
xxx v[2];
И высвобождать память потом не нужно.


Вот здесь забыто else:
Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
if (inet_addr(SERVERADDR) != INADDR_NONE)
            dest_addr[i].sin_addr.s_addr = inet_addr(SERVERADDR);
        //попытка получить IP адрес по доменному
        //имени сервера
        else if (hst[i] = gethostbyname(SERVERADDR))
            //hst->h_addr_list  содержит не массив адресов,
            //а массив указателей на адреса
            ((unsigned long*)&dest_addr[i].sin_addr)[0] = ((unsigned long **)hst[i]->h_addr_list)[0][0];
        else
        {
            printf("Invalid address %s\n", SERVERADDR);
            closesocket(my_sock[i]);
            WSACleanup();
            return -1;
        }



Почему strlen(buff), да ещё плюс один (он-то откуда взялся), когда нужен sizeof(buff):
Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
    recvb=recv(my_sock[1], &buff[0], strlen(buff)+1sizeof(buff), 0);



Теперь о деле. Зачем отравлять в каждый поток одинаковый аргумент my_sock? Отправляйте соответствующий сокет:
Цитата(Toyamatokanava @  28.12.2015,  22:32 Найти цитируемый пост)
       CreateThread(NULL, NULL, priem, my_sock[ i ], NULL, &thID);
Соответственно, схема с while(1) никуда не годится. Если хотите дождаться выполнения потоков, обратите внимание на возвращаемое вызовом CreateThread значение (а возвращаемый хендл всё равно закрывать нужно, иначе утечка хендлов) и функцию WaitForMultipleObjects().


PS Зря я тему перенёс, она скорее касается WinAPI, чем работы с сокетом...

Спасибоо, разобрался вроде. Получилось через создание событий в createevent  и ожидания их через waitformultipleobjects.
PM MAIL   Вверх
feodorv
Дата 30.12.2015, 02:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(Toyamatokanava @  29.12.2015,  18:25 Найти цитируемый пост)
Получилось через создание событий в createevent  и ожидания их через waitformultipleobjects.

Ну, я имел в виду, что хендл потока (возвращаемый вызовом CreateThread) является синхронизирующим объектом, то есть его самого можно использовать в WaitForMultipleObjects():
Код

HANDLE handles[2];

if( (handles[0] = CreateThread( ... my_sock[0] ... )) == NULL ) ... /* error */;
if( (handles[1] = CreateThread( ... my_sock[1] ... )) == NULL ) ... /* error */;

if( WaitForMultipleObjects( 2, handles, TRUE, INFINITE) == WAIT_FAILED ) ... /* error */;

CloseHandle( handles[0] );
CloseHandle( handles[1] );


Хендл потока сигнализируется (переходит в свободное состояние), когда поток реально завершает своё исполнение. Это самый честный подход, так как при использовании событий поток ещё может не завершиться, хотя событие уже сигнализирует о его завершении.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Sajtran
Дата 30.12.2015, 12:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



в теории всё просто, один коннект - один поток
в реале фигня получается - всё это быстро ложится при достаточно примивных атаках

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
Google
  Дата 21.5.2019, 11:03 (ссылка)  





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


 




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


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

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