Форум программистов, компьютерный форум, киберфорум
C++: Сети
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/7: Рейтинг темы: голосов - 7, средняя оценка - 5.00
0 / 0 / 0
Регистрация: 02.01.2014
Сообщений: 3
1

Перестает "работать" сервер при повторном подключении клиента

02.01.2014, 14:23. Показов 1386. Ответов 3
Метки нет (Все метки)

Здравствуйте! Я совершенно недавно начал изучение С++ по этому столкнулся с проблемой которую не осилил.

Вообщем наш препод задал написать сервер-клиент. Клиент отсылает переменную x со случайным значением в диапазоне [-pi;pi] на сервер n раз. Сервер это значение принимает и выполняет расчет по формуле f=cos(x)*sin(x), а результат отсылает обратно на клиент. Клиент полученные с севера значения записывает в txt-файл. На этом по заданию, собственно, все.

Путем гугления и чтения лит-ры - задание выполнил, но вот какая штука:

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

Я пробовал делать возврат в начало программы при завершении цикла while(2)(при потере связи с клиентом) путем помещения тела всей программы в цикл, так же пробовал делать возврат при помощи goto, в надежде, что программа вновь дойдет до момента ожидания клиента и после запуска последнего выполнит все как и в первый раз, но вместо этого мне программа стала выдавать ошибку 10038.

код клиента:
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
94
95
96
97
98
99
100
101
102
103
104
// Код UDP клиента. Задача №5: Отправка n случайных значений в пределах [-pi;pi] с задержкой. получение ответа и запись его в файл.
 
#pragma comment (lib, "ws2_32.lib")
#include<WinSock2.h>
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<fstream>
#include <iomanip>
 
using namespace std;
 
union Ufloat
{
    float f;
    char ch[sizeof(float)];
};
 
 int main()
 {
    Ufloat *A = new Ufloat;
    Ufloat a;
 
    ofstream fout("data_result.txt");
    int n;
    setlocale(LC_ALL,"RUS");
    srand(time(NULL));
    printf("Старт UDP-клиента\n\n");
    Sleep(1000);
 
     // WinSock 
        const int iReqWinsockVer = 2;
        WSADATA wsa_d;
        WORD wVersionRequested = MAKEWORD (2,2);
        int err = WSAStartup(wVersionRequested, &wsa_d);
        if (err !=0)
        {
             printf("Ошибка WSAStartup: %d\n", WSAGetLastError());
        }
        else printf("WinSock - oK...\n");
 
    // открытие и связывание сокета
        struct sockaddr_in Serveraddr;
 
        Serveraddr.sin_family=AF_INET;
        Serveraddr.sin_port=htons(35001);
        Serveraddr.sin_addr.s_addr= inet_addr("127.0.0.1");
 
        SOCKET sock = socket(AF_INET,SOCK_STREAM,0);
        if (sock == INVALID_SOCKET)
        {
            printf("Ошибка при открытии Socket'a: &d\n", WSAGetLastError());
        }
        else printf("Socket  - oK...\n");
 
        int msg = connect(sock, (struct sockaddr *)&Serveraddr, sizeof(Serveraddr));
        if (msg<0)
        {
            printf("Ошибка Connect: %d\n", WSAGetLastError());
        }
        else printf("Connect - oK...\n\n"); 
 
    fout<<"=====================Программа №5==================="<<endl;  
    fout<<"===========Результаты проведенных операций=========="<<endl;
    fout<<"====Функция выполняемая сервером: F=cos(x)*sin(x)===="<<endl;
 
    cout<<"Сколько раз выполнить действие? ";
    cin>>n;
 
    fout<<"===================================================="<<endl; 
    fout<<"        Программа выполнила "<<n<<" операции (-ий)"<<endl;
    fout<<"===================================================="<<endl<<endl;
 
    //Отправка-получение данных
        for (int i=1; i < n; i++)
        {
            //Отправка
            float x = rand() % 628-314;
            A->f = x/100;
            int msg_s = send(sock, A->ch, sizeof(a), 0);
            if (msg_s <= 0)
            {
                printf("\nОшибка отправки сообщения серверу: %d\n", WSAGetLastError());
            }
            else cout<<"Отправлено на сервер: "<<A->f<<endl;
 
            //Получение
            int msg_r=recv(sock, a.ch, sizeof(a), 0);
            if (msg_r <= 0)
            {
                printf("Ошибка чтения сообщения: %d\n", WSAGetLastError());
            }
            else printf("Ответ сервера: %.2f\n\n", a.f);
 
            fout<<"Отправлено на сервер:"<<A->f<<endl;
            fout<<"Ответ сервера: "<<setprecision(2)<<a.f<<endl<<endl;
            Sleep(100);
        };
 
    cout<<"====Все результаты записаны в файл data_result.txt===="<<endl<<"=============в корневой папке с программой============"<<endl<<endl<<endl;
    WSACleanup();
    Sleep(1500);
    return 0;
 };
код сервера:
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
94
95
96
// Код UDP сервера. Задача №5: прием данных с клиента, обработка и отправка результата обратно на клиент.
 
#pragma comment (lib, "ws2_32.lib")
#include<iostream>
#include<WinSock2.h>
#include<stdio.h>
 
using namespace std;
union UFloat
{
    float f;
    char ch[sizeof(float)];
};
 
 int main(void)
 {
        UFloat *A = new UFloat;
        UFloat a;
        setlocale(LC_ALL,"RUS");
 
        printf("Старт UDP-сервера\n\n");
        //Sleep(1000);
     
     // WinSock 
        WSADATA wsa_d;
        WORD wVersionRequested = MAKEWORD (2,2);
        int err = WSAStartup(wVersionRequested, &wsa_d);
        if (err !=0)
        {
             printf("Ошибка WSAStartup: %d\n", WSAGetLastError());
        }
        else printf("WinSock - oK...\n");
 
    // открытие сокета
        SOCKET sock = socket(AF_INET,SOCK_STREAM,0);
        if (sock == INVALID_SOCKET)
        {
            printf("Ошибка при открытии Socket'a: &d\n", WSAGetLastError());
        }
        else printf("Socket - oK...\n");
 
    // Связывание сокета
        struct sockaddr_in localaddr;
        localaddr.sin_family=AF_INET;
        localaddr.sin_addr.s_addr=htonl(INADDR_ANY);
        localaddr.sin_port=htons(35001);
 
        if (bind(sock,(struct sockaddr *) &localaddr, sizeof(localaddr))==SOCKET_ERROR)
        {
            printf("Ошибка вызова Bind: &d\n", WSAGetLastError());
            closesocket(sock);
        }
        else printf("Bind - oK...\n");
 
            int msg = listen(sock, 5);
            if (msg)
            {
                printf("Ошибка Listen: &d\n", WSAGetLastError());
            }
            else printf("Listen - oK... Ждем клиента...\n\n");
 
            sock = accept(sock, NULL, NULL);
            if (sock < 0)
            {
                printf("Ошибка Accept: &d\n", WSAGetLastError());
            }
            else printf("Accept - oK...\n\n");
        
            //for (int i=1; i != 10000; i++)
            while(2)
            {
            //Слушаем клиента
                int msg_r = recv(sock, a.ch, sizeof(a), 0);
                if (msg_r <= 0)
                {
                    printf("Ошибка чтения сообщения: %d\n", WSAGetLastError());
                    break;
                    //goto strt;
                }
                else cout << "Получил сообщение от клиента: " << a.f << endl;
 
            //Отправляем обработанные данные клиенту
 
                A->f = sin(a.f)*cos(a.f); //Выполнение функции 
                printf ("Выполнение операции: F=sin(x)*cos(x)= %.2f\n",A->f);
                int msg_s = send(sock, A->ch, sizeof(a), 0);
                if (msg_s <= 0)
                {
                    printf("Ошибка отправки сообщения клиенту: %d\n", WSAGetLastError());
                }
                else printf("Результат отправлен успешно \n\n");
            };
    WSACleanup();
    system("pause");
    return 0;
  };

Благодарю за внимание.
__________________
Помощь в написании контрольных, курсовых и дипломных работ здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
02.01.2014, 14:23
Ответы с готовыми решениями:

Ошибка "Сервер RPC недоступен" при повторном обращении к Word
Добрый день! Вывожу на печать с формы в документ Word. Все получается. Но при закрытии и при...

При подключении второго клиента к серверу возникает ошибка "IAsyncResult не был получен"
Всем привет, у меня проблема с асинхронными сокетами. Суть: Пишу простенький чат, написал сервер и...

При повторном нажатии на кнопку "Отправить" в приложении "клиент" выскакивает ошибка, что хост принудительно разорвал соединение
Всем привет. Ребят выручайте. Уже 4-й день бьюсь с программой. В общем, тренируюсь создавать...

Чат "Сервер-клиент". На сервер не могу отправить сообщение с клиента
Не могу понять как сделать, чтоб сервер ещё прослушивал и сообщения... Нет ли входящих данных....

3
Ушел с форума
Эксперт С++
16429 / 7393 / 1186
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
02.01.2014, 15:13 2
Цитата Сообщение от RobotiK Посмотреть сообщение
Запускаем клиент, происходит отправка пакетов, как положено, ...
Здесь неверно организован прием данных.
recv за один раз может вернуть байт меньше, чем ему с того конца отправили send-ом.
Пока Вы тестируете программу на локалхосте, этого, скорее всего, не увидите, но в реальных
сетевых условиях все именно так. Обычно recv зовут в цикле, накапливая принятые данные,
пока функция не вернет ноль, что означает, что другая сторона закончила отправку данных
(хотя еще может их принимать), либо пока не будет достигнут конец сообщения. Конец сообщения -
это логическое понятие, определяемое программистом. Например, в HTTP длина сообщения может
определяться заголовком Content-Length, для других протоколов по-другому.

Для Вашей задачи подойдет такая, к примеру, схема:

1) Запускается сервер, создает сокет, выполняет bind, listen и accept, переходя к ожиданию
входящих подключений.

2) Запускается клиент, создает сокет, выполняет коннект, соединяясь с сервером.

3) Сервер, приняв входящее подключение и получив новый сокет, создает для его обработки
отдельный поток, после чего снова переходит в ожидание входящих подключений (accept).
Можно и однопоточный вариант, но тогда для поддержки нескольких одновременных подключений
придется городить огороды с select или асинхронным I/O, а вариант с потоком на клиента (thread
per connection model) проще.

4) Клиент отправляет данные функцией send.

5) Сервер (в отдельном потоке) в цикле вычитывает данные функцией recv, накапливая их в буфере.

6) Клиент зовет shutdown(SD_SEND), сообщая серверу, что больше не будет отправлять данных.

7) Сервер (поток), вызывая в очередной раз recv, получает 0 и переходит к обработке полученных данных.

8) Клиент начинает вычитывать данные функцией recv, тоже в цикле, тоже пока не получит 0.

9) Сервер (поток), обработав запрос и сформировав для него ответ, отдает его клиенту функцией send,
после чего тоже закрывает свой конец соединения с помощью shutdown(SD_SEND).

10) Клиент получает recv == 0, печатает ответ сервера и завершает работу.

11) Сервер (поток) завершает работу. При этом основной поток все это время находится в цикле accept и
может принимать подключения от других клиентов.

Цитата Сообщение от RobotiK Посмотреть сообщение
printf("Старт UDP-клиента\n\n");
Цитата Сообщение от RobotiK Посмотреть сообщение
printf("Старт UDP-сервера\n\n");
А Вы уверены, что это точно UDP ? Как бы балл не сняли за такое вопиющее "нарушение"...

Цитата Сообщение от RobotiK Посмотреть сообщение
Запускаем клиент, происходит отправка пакетов, как положено, и после выполнения своей задачи, клиент закрывается. После этого, по идеи, сервер должен продолжить свою работу в прежнем режиме и при повторном запуске клиента выполнить операцию заново, но вот тут все не так, как при первом запуске клиента. Ничего не работает.
Покажите мне то место, из которого следует, что сервер должен продолжить свою работу.
В коде сервера accept (прием подключений) вызывается лишь раз, после этого сервер обрабатывает
запрос и отрубается. Как написали - так он и работает.
1
0 / 0 / 0
Регистрация: 02.01.2014
Сообщений: 3
02.01.2014, 15:57  [ТС] 3
Цитата Сообщение от Убежденный Посмотреть сообщение
А Вы уверены, что это точно UDP ? Как бы балл не сняли за такое вопиющее "нарушение"...
Это вопрос уже думаю к моему преподавателю, т.к. он обозначил что это UDP и дал основные функции для реализации обмена пакетов между сервером и клиентом, которые и использовал для написания программы, так что тут думаю, он не будет придираться, тем более учитывая тот факт, что программированию он посвятил лишь 2 пары, оставив все это на самостоятельное изучение

Цитата Сообщение от Убежденный Посмотреть сообщение
Покажите мне то место, из которого следует, что сервер должен продолжить свою работу. В коде сервера accept (прием подключений) вызывается лишь раз, после этого сервер обрабатывает
запрос и отрубается. Как написали - так он и работает.
Я пытался этого добиться путем возврата в начало программы после выполнения цикла, но не получилось, по этому прикрепил код "одноразовой" операции который работает. Хотя признаю что возможно сказал глупость, ведь в этом всем я, увы, мало компетентен...

Цитата Сообщение от Убежденный Посмотреть сообщение
Для Вашей задачи подойдет такая, к примеру, схема:
Я попробую последовать вашему совету, надеюсь получится и к сроку уложусь


Благодарю вас за ответ, даже не ожидал что кто-то так скоро откликниться)
0
Ушел с форума
Эксперт С++
16429 / 7393 / 1186
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
02.01.2014, 18:33 4
Цитата Сообщение от RobotiK Посмотреть сообщение
Это вопрос уже думаю к моему преподавателю, т.к. он обозначил что это UDP и дал основные функции для реализации обмена пакетов между сервером и клиентом, которые и использовал для написания программы, так что тут думаю, он не будет придираться, тем более учитывая тот факт, что программированию он посвятил лишь 2 пары, оставив все это на самостоятельное изучение
Но все-таки исправьте. Здесь используется TCP, а UDP - это совсем другое.
UDP - это дейтаграммный протокол, он работает без установки соединения и
не гарантирует ни доставки данных, ни их порядка.
UDP-сокет создается с параметрами SOCK_DGRAM и IPPROTO_UDP.

Цитата Сообщение от RobotiK Посмотреть сообщение
Благодарю вас за ответ, даже не ожидал что кто-то так скоро откликниться)
Да не за что
Праздники в разгаре, вот и народ весь в оффлайне.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
02.01.2014, 18:33

При подключении VPN интернет перестаёт работать.
Добрый день! на прошлой неделе на работе сказали из дома работать. подрубили впн .. только вот...

Сервер.Загрузка "1" ядра процессора на ~100%, "2" на ~5%!!!? (при многопроц. системе) АС "Смета" БД FB 2.5
Добрый день(вечер)!!! Ситуация: Существует серв с бд для бухгалтерии, вообщем АС &quot;СМЕТА&quot; . СУБД...

При подключении ReportViewer перестает работать на другом комьютере
Проект разрабатываю на своем компьютере, потом exe модуль переношу на другие компьютеры. Все было...

При подключении VPN часть программ перестает работать
При включении VPN часть программ перестает работать. Пропадает доступ к SQL Server. Скайп для...


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

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.