Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.78/9: Рейтинг темы: голосов - 9, средняя оценка - 4.78
0 / 0 / 1
Регистрация: 10.09.2020
Сообщений: 28

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

10.09.2020, 15:08. Показов 2017. Ответов 13

Студворк — интернет-сервис помощи студентам
Доброго времени суток.
В си я не очень хорошо разбираюсь, но появилась необходимость создать сервер, который принимал бы данные от нескольких клиентов и записывал данные в отдельные файлы. На данный момент написан сервер, который принимает данные от одного пользователя, но как сделать это для нескольких, я не могу понять и гугл мне пока что не смог с этим помочь. Поэтому прошу помощи и заранее выражаю огромную благодарность тем, кто ответит.

Далее привожу имеющийся код:
Сервер

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
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
 
#define SERVER_PORT 3128
 
int main( void )
{
    int fd;
    FILE *file;
 
    if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
        perror( "socket failed" );
        return 1;
    }
 
    struct sockaddr_in serveraddr;
    memset( &serveraddr, 0, sizeof(serveraddr) );
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(SERVER_PORT);
    serveraddr.sin_addr.s_addr = htonl( INADDR_ANY );   
                                                                
    if ( bind(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0 ) {
        perror( "bind failed" );
        return 1;
    }
 
    char buffer[200];
    for ( int i = 1; i < 3; i++ ) {
        int length = recvfrom( fd, buffer, sizeof(buffer) - 1, 0, NULL, 0 );
        if ( length < 0 ) {
            perror( "recvfrom failed" );
            break;
        }
        buffer[length] = '\0';
        file = fopen("server.txt", "a+");
        fprintf(file, "%d: '%s'\n", i, buffer);
    }
    fclose(file);
    close( fd );
}
Клиент

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
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
 
#define SERVER_PORT 3128
 
int main( void )
{
    int fd;
    if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
        perror("socket failed");
        return 1;
    }
 
    struct sockaddr_in serveraddr;
    memset( &serveraddr, 0, sizeof(serveraddr) );
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(SERVER_PORT);
    serveraddr.sin_addr.s_addr = htonl( 0x7f000001 );
    
    for ( int i = 0; i < 2; i++ ) {
        if (sendto( fd, "hello", 5, 0, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0 ) {
            perror( "sendto failed" );
            break;
        }
        printf( "message sent\n" );
    }
 
    close( fd );
}
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
10.09.2020, 15:08
Ответы с готовыми решениями:

Поставить сервер в режим ожидания нескольких клиентов
Здравствуйте. Суть программы в том,что она считает количество символов встречаемых в текстовом файле,но работает только с одним...

Задача: сделать сервер для нескольких клиентов
Вот есть сервер, который рассчитан только на 1 клиент. Задача: сделать сервер для нескольких клиентов. Как это сделать? Сам сервер: ...

Один jsp с содержанием, принимающий все http-запросы к сайту.
Тогда не придется в каждой JSP или сервлете вводить Здравствуйте! Есть вопрос: есть сайт на jsp. Любая страница формируется следующим...

13
48 / 46 / 18
Регистрация: 27.04.2016
Сообщений: 169
14.09.2020, 17:46
Если нет жесткого требования работать с UDP, то все это легко реализуется с помощью TCP. Создаем сокет, который принимает запрос на подключение от клиента, а потом, после установления контакта, запускаем отдельный поток/процесс, который непосредственно общается с клиентом.
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
14.09.2020, 17:53
Цитата Сообщение от annaifel Посмотреть сообщение
который принимал бы данные от нескольких клиентов
Как он их должен отличать?
0
0 / 0 / 1
Регистрация: 10.09.2020
Сообщений: 28
14.09.2020, 18:03  [ТС]
Нужно именно для UDP. Вроде как можно использовать для этой цели select, но пока я до конца не разобралась как это должно работать. Поэтому вопрос можно немного переформулировать. Как реализовать select при UDP протоколе?

Добавлено через 7 минут
На этот вопрос у меня пока нет ответа, в любом случае нужно, чтобы сервер не отключался после первого соединения с клиентом, а был готов либо к повторному соединению. Возможно вопрос сформулирован не совсем верно.
0
48 / 46 / 18
Регистрация: 27.04.2016
Сообщений: 169
14.09.2020, 18:03
Здесь Vourhey правильно подметил, что нужно этих клиентов друг от друга различать. В UDP это можно сделать с помощью сравнения IP-адреса и порта того, от кого пришел пакет. Для этого естественно нужно держать список клиентов, которые уже присылали пакеты, а нового клиента добавлять в этот список. Для того, чтобы понять, как использовать select достаточно посмотреть пример в man select.
1
0 / 0 / 1
Регистрация: 10.09.2020
Сообщений: 28
16.09.2020, 12:19  [ТС]
Я понимаю, что нужно проводить сравнение, но абсолютно не понимаю механизм реализации этого процесса. Где можно почитать про это или может есть примеры исполнения такой задачи?
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
16.09.2020, 12:26
annaifel, предпоследний и последний параметры функции recvfrom.
1
0 / 0 / 1
Регистрация: 10.09.2020
Сообщений: 28
18.09.2020, 12:37  [ТС]
Спасибо за ваши ответы.

Но как мне помогут порты, если они динамически назначаются, и два последовательных обращения с одного клиента к серверу происходит с разных портов. Ведь тогда сервер будет одного и того же клиента воспринимать как разных? Или порты должны быть заданы статически у каждого клиента? Или я не понию чего-то очевидного?
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
18.09.2020, 12:58
annaifel, на порты ориентироваться не нужно. Либо разделяешь клинтов по айпи. Либо расширяешь свой формат сообщений, чтобы клиент присылал в каждом сообщении ключ, который позволяет его идентифицировать.
1
0 / 0 / 1
Регистрация: 10.09.2020
Сообщений: 28
24.09.2020, 09:48  [ТС]
Появился новый вопрос по этой теме. На одном компьютере клиент и сервер общаются прекрасно, но как только клиент был перенесён на другой компьютер в той же локальной сети, тогда и данные с клиента перестали приходить на сервер. Что может быть не так? Читала про то, что проблема может быть в брандмауэре, отключала, не помогло.

Сервер:

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
#include <arpa/inet.h> 
#include <errno.h> 
#include <netinet/in.h> 
#include <signal.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/inotify.h>
 
#define PORT 47890  
#define MAXLINE 1024 * 1024 * 7
 
int main() 
{ 
    int udpfd, nready, maxfdp; 
    char buffer[MAXLINE]; 
    char cliIP[40];
    int cliPORT;
    pid_t childpid; 
    fd_set rset; 
    ssize_t n; 
    socklen_t len; 
    const int on = 1; 
    struct sockaddr_in cliaddr, servaddr;
    FILE *file;
    void sig_chld(int); 
 
    udpfd = socket(AF_INET, SOCK_DGRAM, 0);  
    memset( &servaddr, 0, sizeof(servaddr) ); 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    servaddr.sin_port = htons(PORT); 
  
    bind(udpfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); 
    listen(udpfd, 10); 
  
    FD_ZERO(&rset); 
  
    maxfdp = udpfd + 1; 
 
    for (;;) { 
        FD_SET(udpfd, &rset); 
        nready = select(maxfdp, &rset, NULL, NULL, NULL);  
 
        if (FD_ISSET(udpfd, &rset)) {
            len = sizeof(cliaddr);
            memset(buffer, 0, sizeof(buffer));
            memset(cliIP, 0, sizeof(cliIP));
            n = recvfrom( udpfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&cliaddr, &len );
            if (n < 0) {
                perror( "recvfrom failed" );
                break;
            }
            cliPORT = cliaddr.sin_port;
            inet_ntop(AF_INET, &cliaddr.sin_addr, cliIP, sizeof(cliIP));
            buffer[n] = '\0';
            strcat( cliIP, ".txt");
            file = fopen(cliIP, "a+");
            fprintf(file, "%s, %d :\n %s\n", cliIP, cliPORT, buffer);
            fclose( file );          
        } 
    } 
}
Клиент:

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
#include <arpa/inet.h> 
#include <netinet/in.h> 
#include <poll.h>
#include <errno.h> 
#include <signal.h>
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <sys/inotify.h>
#include <unistd.h> 
#include <assert.h>
#include <malloc.h> 
 
#define PORT  47890  
#define MAXLINE 65536
#define EVENT_SIZE  (sizeof(struct inotify_event))
 
...
 
int server_connection(char* message) 
{ 
    int sockfd; 
    char buffer[MAXLINE]; 
    struct sockaddr_in servaddr; 
  
    int n, len; 
 
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 
        printf("socket creation failed"); 
        exit(0); 
    } 
  
    memset(&servaddr, 0, sizeof(servaddr)); 
  
    servaddr.sin_family = AF_INET; 
    servaddr.sin_port = htons(PORT); 
    servaddr.sin_addr.s_addr = htonl( INADDR_ANY ); 
    sendto(sockfd, (const char*)message, strlen(message), 0, (const struct sockaddr*)&servaddr, 
           sizeof(servaddr)); 
    
    close(sockfd); 
    return 0; 
}
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
24.09.2020, 10:35
annaifel, чтобы не гадать, пингануть сервер с клиента, чтобы убедиться, что хост находится. Посмотреть вывод iptables - L на сервере. Научиться работать с Wireshark и посмотреть пакеты приходящие на порт. Код не смотрел)))
1
0 / 0 / 1
Регистрация: 10.09.2020
Сообщений: 28
24.09.2020, 14:06  [ТС]
Клиент не может подключиться к серверу (connect: Network is unreachable), а сервер назначает себе ip 0.0.0.0, хотя на самом деле у него должен быть другой ip. Вывод iptables -L на сервере ничего не выдаёт, кроме ошибки, но тут ещё есть сложность в том, что работаю не на полноценной linux'овской ос, а на wsl, и не знаю, где искать недостающий каталог, который он от меня хочет получить. Также на сервере я задаю один порт, а использует он другой, что тоже пока непонятно.
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
24.09.2020, 14:35
Цитата Сообщение от annaifel Посмотреть сообщение
а сервер назначает себе ip 0.0.0.0, хотя на самом деле у него должен быть другой ip
Если у сервер нет адреса, то к чему должен подключаться клиент?

Добавлено через 1 минуту
Цитата Сообщение от annaifel Посмотреть сообщение
но тут ещё есть сложность в том, что работаю не на полноценной linux'овской ос, а на wsl
Ахах, ну тогда понятно, почему iptables не работает.
Цитата Сообщение от annaifel Посмотреть сообщение
Также на сервере я задаю один порт, а использует он другой, что тоже пока непонятно.
Короче, разбирайся с инфраструктурой, приложение тут пока не при чем.
1
0 / 0 / 1
Регистрация: 10.09.2020
Сообщений: 28
24.09.2020, 14:46  [ТС]
Цитата Сообщение от annaifel Посмотреть сообщение
Также на сервере я задаю один порт, а использует он другой, что тоже пока непонятно.
С портом я разобралась, с ip пока не понимаю что делать, но буду искать информацию...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
24.09.2020, 14:46
Помогаю со студенческими работами здесь

Сервер UDP принимающий/передающий пакеты от всех/всем клиентам
Написан клиент, который передает пакеты на север. Помощь нужна в следующем. Мне нужно чтобы приходящие пакеты на сервер сразу были...

Серверное приложение, обслуживающее запросы клиентов по протоколу HTTP
Разработать Серверное приложение WinAPI, обслуживающее запросы клиентов по протоколу HTTP. Клиенты отправляют серверу коэффиценты...

Запросы: сумма заказов клиентов за выбранный промежуток времени
Есть запрос который выводит сумму заказов клиентов за выбранный промежуток времени. В запросе выводят только клиентов которые...

Серверное приложение WinAPI, обслуживающее запросы клиентов по протоколу ТСР
Разработать Серверное приложение WinAPI, обслуживающее запросы клиентов по протоколу ТСР. Клиенты отправляют серверу коэффиценты...

Работа с базой нескольких клиентов
Поделитесь опытом, как к одной разделенной базе, находящейся на рабочем месте 'А', подключиться с компьютера 'Б'. Что надо, чтобы...


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

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru