Форум программистов, компьютерный форум, киберфорум
C++: Сети
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.80/15: Рейтинг темы: голосов - 15, средняя оценка - 4.80
5 / 5 / 1
Регистрация: 08.05.2011
Сообщений: 121

Общение между потоками с разными сокетами

02.07.2012, 10:52. Показов 3305. Ответов 19
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте! Недавно начал заниматься сокетами, возникла задача сделать так, чтобы каждый пользователь подключавшийся к серверу получал отдельный поток. Но при этом мне нужно чтобы между этими потоками(функциями DWORD WINAPI SexToClient(LPVOID c_s) ) можно было передавать сообщения.

Код сервера:
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
#include "stdafx.h"
#include <winsock2.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib,"Wsock32.lib")
using namespace std;
 
// макрос для печати количества активных
// пользователей 
#define PRINTNUSERS if (nclients)\
cout << nclients << " user on-line" << endl;\
else cout << "No User on line" << endl;
 
// прототип функции, обслуживающий
// подключившихся пользователей
DWORD WINAPI SexToClient(LPVOID client_socket);
 
//количество активных пользователей 
int nclients = 0;
 
int main(int argc, char ** argv)
{
    char buf[255], res[100], b[255], *Res;
 
    std::cout << "Server is initializing ...";
    //инициализация библиотеки сокетов
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD(2, 2);
    WSAStartup( wVersionRequested, &wsaData );
 
    //создаем потоковый TCP сокет
    SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
 
    struct sockaddr_in local;
    local.sin_family      = AF_INET;
    local.sin_port        = htons(1280);
    local.sin_addr.s_addr = htonl(INADDR_ANY);
 
    //связываем сокет с адресом
    int c = bind( s, (struct sockaddr*)&local, sizeof(local) );
 
    //помещаем сокет в состояние прослушивания
    int r = listen(s,5);
 
    SOCKET s2;
    //структура определяет удаленный адрес,
    // с которым соединяется сокет
    sockaddr_in remote_addr;
    int size  = sizeof(remote_addr);
    //цикл извлечения запросов на подключение из очереди
    while(s2 = accept( s, (struct sockaddr*)&remote_addr, &size))
    {
        nclients++;
        hostent *hst;
        hst=gethostbyaddr((char *)
            &remote_addr.sin_addr.s_addr,4,AF_INET);
        cout << hst->h_name << inet_ntoa(remote_addr.sin_addr) << "new connect" << endl;
        PRINTNUSERS
            // Вызов нового потока для обслужвания клиента
        DWORD thID;
        CreateThread(NULL,NULL,SexToClient,&s2,NULL,&thID);
 
    }
    
    return 0;
}
 
//функция создается в отдельном потоке и обслуживает очередного клиента независимо
 
DWORD WINAPI SexToClient(LPVOID c_s)
{
    SOCKET my_s;
    my_s=((SOCKET *) c_s)[0];
    char buff[20*1024];
    char b[255];
 
    
        //принимаем данные - отправляем данные
    while ( recv( my_s, b, sizeof(b), 0) != SOCKET_ERROR ) {
        cout << b << endl;
        
        send(my_s,b,sizeof(b),0);
    }
 
    //если мы здесь, клиент дисконнектед
    nclients--;
    cout<<"disconnect" << endl;
    // закрываем сокет
    closesocket(my_s);
    return 0;
}
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
02.07.2012, 10:52
Ответы с готовыми решениями:

Как правильно работать с сокетами и потоками
Есть сервер и пара клиентов, которые к нему подключаются... Использую потоки, -каждый сокет в своем потоке. Клиенты передают на сервер...

Какая разница между различными сокетами (например, между 775 и 1155)?
Обясните пожалуйста какая разница между сокетами, пример есть сокет 775 и 1155 я понимаю что разем не тот процессора другие но! как насчет...

Работа с потоками с разными приоритетами
Дали такое задание: Напишите программу, которая создает один поток и позволяет пользователю изменять приоритет процесса и потока и...

19
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
02.07.2012, 11:02
1) плохой код. Нет проверок результатов работы функций, привыкай все делать правильно
2) сделай общее хранилище для клиентов, не забывая при этом про многопоточность и общие ресурсы.
0
5 / 5 / 1
Регистрация: 08.05.2011
Сообщений: 121
02.07.2012, 11:04  [ТС]
Цитата Сообщение от villu Посмотреть сообщение
1) плохой код. Нет проверок результатов работы функций, привыкай все делать правильно
2) сделай общее хранилище для клиентов, не забывая при этом про многопоточность и общие ресурсы.
тестовый код, пока хочу чтобы все работало хоть как-то.

как понять общее хранилище? каким оно может быть?
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
02.07.2012, 11:08
ну раз тестовый ... )

общее, как например, вектор из сокетов, а еще лучше придумать какую-то структуру с некоторой информацией о соединении. и потом можно что-то типа map<int, inf_struct>, где int - это сокет.

Если надо отправлять всем, то просто проходишь по всей мапе и рассылаешь. Удаление и добавление и работа с сокетами должны быть защищены, например, критической секцией.
1
5 / 5 / 1
Регистрация: 08.05.2011
Сообщений: 121
02.07.2012, 12:41  [ТС]
int - номер сокета?
то есть что-то вроде:

C++
1
2
3
4
5
6
7
8
9
10
11
12
struct conn {
    char * client_name;
    SOCKET client_socket;
};
 
map<int, conn> conns;
 
connection = new conn;
connection-> client_name="client x";
connection-> client_socket = my_socket;
 
conns[0] = connection;
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
02.07.2012, 12:46
int - номер сокета?
Ну в твоем случае это тот самый SOCKET клиента.

смысле в том, чтобы делать conns[0] нет, потому как map это дерево. стало быть лучше так

C++
1
conns.insert( std::make_pair( my_socket, *connection ) )
Только лучше, наверно, вместо char* сделать std::string
1
5 / 5 / 1
Регистрация: 08.05.2011
Сообщений: 121
02.07.2012, 15:08  [ТС]
а выводить из мап как?
C++
1
cout << "элемент => " << conns.find(my_s)->second.client_name << endl;
на это говорит
отсутствует оператор "<<", соответствующий этим операндам

и ещё вопрос)
можно ли из сокета достать имя хоста с которым он связан?
C++
1
2
3
hostent *hst;
        hst=gethostbyaddr((char *)
            &remote_addr.sin_addr.s_addr,4,AF_INET);
то есть что-то вроде этого, только используя только сокет my_s
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
02.07.2012, 15:19
C++
1
cout << "элемент => " << conns.find(my_s)->second.client_name << endl;
плохо. Потому как он его может там не найти.
лучше найти в переменную - итератор и потом выводить.
можно ли из сокета достать имя хоста с которым он связан?
Можно. Сначала нужно использовать getpeername, чтобы получить эту структуру.
0
5 / 5 / 1
Регистрация: 08.05.2011
Сообщений: 121
02.07.2012, 15:33  [ТС]
C++
1
2
3
4
5
map<int, conn>::const_iterator itr;
 
            for(itr = conns.begin(); itr != conns.end(); ++itr){
                cout << "Key: "  << (*itr).second.client_name;
            }
отсутствует оператор "<<", соответствующий этим операндам

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//получаем адрес
    SOCKADDR peer;
    int peerlen = sizeof(peer);
    
    if (0 == getpeername(my_s, &peer, &peerlen))
    {
      printf("\nConnect from %s:%i", 
        inet_ntoa(((SOCKADDR_IN *)&peer)->sin_addr), 
        ntohs(((SOCKADDR_IN *)&peer)->sin_port));
    }
    cout << endl;
    //получаем имя хоста
    hostent *hst;
        hst=gethostbyaddr((char *)
            &peer,4,AF_INET);
        cout << hst->h_name << endl;
выдает хостнейм "ANantes-553-1-163-223.w2-0.abo.wanadoo.fr"
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
02.07.2012, 15:41
у тебя client_name какого типа? char *?
0
5 / 5 / 1
Регистрация: 08.05.2011
Сообщений: 121
02.07.2012, 15:42  [ТС]
Цитата Сообщение от villu Посмотреть сообщение
у тебя client_name какого типа? char *?
я на string поменял как ты посоветовал
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
02.07.2012, 15:50
тогда странно.
а #include <string> есть?
1
5 / 5 / 1
Регистрация: 08.05.2011
Сообщений: 121
02.07.2012, 20:42  [ТС]
итог пока:
клиенты записываются в мапс
о них получается любая информация

теперь не получается отправить информацию всем клиентам:
C++
1
2
3
4
map<int, conn>::const_iterator itr;
        for(itr = conns.begin(); itr != conns.end(); ++itr){
            send((*itr).second.client_socket,b,sizeof(b),0);
        }
написал такой код в цикле while(принятия-отправки сообщений от клиентов) функции DWORD WINAPI SexToClient

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

fix: отправляет другим, но не всем и как-то странно. пытаюсь разобраться как
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
02.07.2012, 20:45
send ошибку не возвращает?
Клиенты точно есть в мапе?

Добавлено через 1 минуту
и еще. мапа то глобальная?
1
5 / 5 / 1
Регистрация: 08.05.2011
Сообщений: 121
02.07.2012, 21:24  [ТС]
Цитата Сообщение от villu Посмотреть сообщение
send ошибку не возвращает?
Клиенты точно есть в мапе?

Добавлено через 1 минуту
и еще. мапа то глобальная?
C++
1
2
3
4
5
6
7
8
                try
                  {
                    send(my_s,b,sizeof(b),0);
                  }
                  catch(...)
                  {
                    cout << "error:" << endl;
                  }
сделал такую конструкцию, ошибок не заметил
мапа да, создается перед мэйн:
C++
1
2
3
map<int, conn> conns;
int main(int argc, char ** argv)
......................
клиенты в мапе, работает вывод всех имен, сравнение по сокетам
C++
1
if((*itr).first != my_s )
p.s. теперь вообще другим сокетам не отправляет(изменений вроде не делал особых)
и если например, я поработал с одного клиента поотправлял сообщения, то если я начинаю работать с другим клиентом, ему начинают выводиться те сообщения, которые должны были быть отправлены ему до этого
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
02.07.2012, 21:26
C++
1
2
3
4
5
6
7
8
try
                  {
                    send(my_s,b,sizeof(b),0);
                  }
                  catch(...)
                  {
                    cout << "error:" << endl;
                  }
send не кидает исключений, он возвращает -1 в случае ошибки. Ну это если у тебя не какой-то свой send
1
5 / 5 / 1
Регистрация: 08.05.2011
Сообщений: 121
02.07.2012, 21:47  [ТС]
поставил проверку на -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
#include "stdafx.h"
#include <winsock2.h>
#include <iostream>
#include <stdlib.h>
#pragma comment(lib,"Wsock32.lib")
using namespace std;
 
int main(int argc, char ** argv)
{
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD(2, 2);
 
    WSAStartup( wVersionRequested, &wsaData );
 
 
    //создаем потоковый(sock_stream) сокет
    //Нулевое значение - по умолчанию: TCP - для потоковых сокетов
    SOCKET s = socket(AF_INET,SOCK_STREAM,0);
 
    struct sockaddr_in peer;
    //семейство используемых протоколов. Для Интернет - приложений - AF_INET.
    peer.sin_family = AF_INET;
    peer.sin_port   = htons(1280);
    // т.к. клиент и сервер на одном компьютере, пишем адрес 127.0.0.1
    peer.sin_addr.s_addr = inet_addr("127.0.0.1");
    HOSTENT *hst;
    
    //посылаем запрос на открытие соединения
    connect(s,(struct sockaddr*) &peer,sizeof(peer));
 
    char buf[255],b[255];
    
    while(true) {
        std::cout << "Enter the string, please" << std::endl;
        std::cin.getline(buf, 100, '\n');
        //посылаем запрос
        send(s, buf,sizeof(buf), 0);
        //принимаем данные
        if (recv(s, b,sizeof(b), 0) != 0) {
            //Удаление ненужных символов в конце строки
            b[strlen(b)]='\0';
            std::cout << "RESULT: ";
            std::cout << b << std::endl;
            std::cout << std::endl;
        }
    }
    closesocket(s);
    WSACleanup();
 
    system("PAUSE");
    return 0;
}
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
02.07.2012, 21:54
разумеется можно.
смотреть
select
или I/O Completion Ports
или boost::asio

вообще от задачи зависит. Когда, например, клиент должен отправлять сообщения?

В твоем случае, можно под прием поток выделить.
1
5 / 5 / 1
Регистрация: 08.05.2011
Сообщений: 121
02.07.2012, 22:36  [ТС]
Цитата Сообщение от villu Посмотреть сообщение
разумеется можно.
смотреть
select
или I/O Completion Ports
или boost::asio

вообще от задачи зависит. Когда, например, клиент должен отправлять сообщения?

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

про i/o читаю пока, я так понял это принцип взаимодействия клиент сервер, только асинхронный, в отличии от того который я применяю

а вот про поток для приема:
то есть у меня например, будет создаваться поток, где я буду только читать сообщения, и далее будет while цикл где я буду только отправлять сообщения?

Добавлено через 23 минуты
update: сделал поток для чтения, все работает отлично) спасибо)
0
 Аватар для gore-lykovoe
32 / 32 / 3
Регистрация: 04.04.2010
Сообщений: 414
02.07.2012, 23:09
Цитата Сообщение от vvApache Посмотреть сообщение
все работает отлично)
Выложи код клиента и сервера пожалуйста) Тоже изучаю эту тему сейчас)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
02.07.2012, 23:09
Помогаю со студенческими работами здесь

Сложить 3 пары TextBox разными потоками
Прошу помощи сам не разберусь, нужна программа которая будет складывать рандомно 3 пары TextBox разными потоками каждую пару с разной...

Подсчет статистики по файлу разными потоками
Не смог до конца разобраться в коде. Делает ли код то, чего требует задание? Задание: Необходимо написать программу, ведущую подсчет...

Работа с потоками с разными приоритетами. Функция GetThreadTimes()
Необходимо написать программу, выполняющую следующее: Посчитайте время выполнения потока с разными приоритетами с помощью функции...

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

tbb parallel_for чтение одного участка памяти разными потоками
Добрый день. Предположим, нужно распараллелить свертку одного и того же изображения разными фильтрами (использую tbb:: parallel_for)- в...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru