С Новым годом! Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 4.83
mh-coder
-4 / 26 / 3
Регистрация: 01.02.2014
Сообщений: 813
#1

Сокеты: после вызова send программа зависает на функции recv - C++

25.08.2014, 16:18. Просмотров 2108. Ответов 21
Метки нет (Все метки)

Извеняюсь за такое назание темы, но уже перепробовал 100 вариантов и постоянно выкидывает данное предупреждение, уже и не знаю что блин написать))

Проблема в следующем:
Изучаю сокеты и столкнулся с небольшой проблемой, в данном коде я соеденяюсь с локкал хостом на порту 2222 дабы , и прописую данный порт в прокси в браузере, дабы отлавливать его заголовки, проблема в следующем,
1) после использования функции send - код зависает над функцией recv и не двигается с места, немогу понять почему
2) если убрать send то всё работает нормально, но recv постоянно возвращает заголовки отправлнные в первый раз не реагируя на те сайты которые открываются в браузере в дальнёйшем.


main.cpp

C++ (Qt)
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
// Mysock2.cpp: определяет точку входа для консольного приложения.
//
 
#include "stdafx.h"
#include "Server.h"
 
 
 
int _tmain(int argc, _TCHAR* argv[])
{
 
 
 
    char data[1000] = {NULL};
 
    Client c;
    Server b;
    b.LoadWinsoсk();
    b.CreateSocket();
 
    c.LoadWinsoсk();
    c.CreateSocket();
 
    b.Bind("127.0.0.1",2222,SOMAXCONN);
    b.Listen();
    b.Accept(c);
 
 
 
    while(true){
        c.RecvData(data,1000);  
 
    //  c.SendData(data,1000);
        cout<<c.GetError()<<"\n"<<data<<"\n";
 
 
    }
 
    return 0;
}

BaseNet.h

C++ (Qt)
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
#pragma once
#include <Windows.h>
#include <Winsock.h>
#pragma comment( lib, "Ws2_32.lib" )
 
 
class BaseNet
{
public:
    BaseNet(); 
    virtual ~BaseNet();
 
    bool LoadWinsoсk(void); // метод згрузки библиотеки Ws2_32.dll
    bool CreateSocket(void); // метод создания  сокета
    bool SendData(LPCSTR,const int &); // метод  передачи данных
    bool RecvData(LPSTR,const int &); // метод полученя данных
    bool CloseSocket(void); // метод закрытия сокета
    bool UnloadWinsock(void);// метод выгрузки Ws2_32.dll
    int GetError(void)const; // метод возврата кода ошибки
    int GetSendSize(void)const; //метод возврата количеств переданых байтов методом SendData
    int GetRecvSize(void)const;// метод возврата киличества принятых байтов методом vData
    
 
protected:
 
    WSADATA ws; //структура
    SOCKET Socket;
    struct sockaddr_in addr; //структура информации:ip, post, семейство протоколов
    int err; //код ошибки
    int size_send, size_recv;// количество переданных/принятых байт
 
private:
 
    bool Load_WSDATA;
};
BaseNet.cpp

C++ (Qt)
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "stdafx.h"
#include "BaseNet.h"
 
 
BaseNet::BaseNet()
{
 
    memset(&this->ws, 0, sizeof(ws));
    this->Socket = NULL;
    memset(&this->addr, 0, sizeof(addr));
    this->err = 0;
    this->size_send = 0, this->size_recv = 0;
    this->Load_WSDATA = false;
}
 
 
BaseNet::~BaseNet()
{
 
    this->UnloadWinsock();
}
 
 
bool BaseNet::LoadWinsoсk(void){
 
    if (WSAStartup(0x0202, &this->ws))
    {
        this->err = WSAGetLastError();
        return false;
    }
    this->Load_WSDATA = true;
    return true;
}
 
 
bool BaseNet::CreateSocket(void){
 
    this->Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    if (this->Socket == SOCKET_ERROR){
 
        this->err = WSAGetLastError();
        return false;
    }else{
        return true;
    }
 
}
 
 
bool BaseNet::SendData(LPCSTR _pbuf, const int & size_buf){
 
    this->size_send = send(this->Socket, _pbuf, size_buf, 0);
 
    if (this->size_send == SOCKET_ERROR){
 
        this->err = WSAGetLastError();
        return false;
    }
    else{
        return true;
    }
 
}
 
 
bool BaseNet::RecvData(LPSTR _pbuf, const int & size_buf){
    
 
    this->size_recv = recv(this->Socket, _pbuf, size_buf, 0);
 
    if (this->size_recv == SOCKET_ERROR){
 
        this->err = WSAGetLastError();
        return false;
    }
    else{
        return true;
    }
 
}
 
 
bool BaseNet::CloseSocket(void){
 
    if (closesocket(this->Socket) == SOCKET_ERROR){
        this->err = WSAGetLastError();
        return false;
    }
    else{
        return true;
    }
 
}
 
bool BaseNet::UnloadWinsock(void){
    if (this->Load_WSDATA){
    if (WSACleanup() == SOCKET_ERROR){
        this->err = WSAGetLastError();
        return false;
    }
    else{
        return true;
    }
}
    return false;
}
 
 
int BaseNet::GetError(void)const{
    return this->err;
}
 
 
int BaseNet::GetSendSize(void)const{
    return this->size_send;
 
}
int BaseNet::GetRecvSize(void)const{
    return this->size_recv;
}
Server.h

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once
#include "BaseNet.h"
#include "Client.h"
class Server : public BaseNet
{
public:
    Server();
    virtual ~Server();
 
    bool Bind( LPCSTR       = "127.0.0.1",  // По умолчанию IP локальный, для удобства тестирования
        const UINT& = 33333,        // По умолчанию порт 33333
        const int&  = SOMAXCONN );  // По умолчанию SOMAXCONN клиентов будет ожидать сервер
 
 
    bool Listen(void); // метод прослушивания подключения клиентов
    bool Accept(Client &); // метод приёма поключения клиента
 
    // Остановка сервера
    bool StopServer( void );
 
 
};
Server.cpp

C++ (Qt)
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
#include "stdafx.h"
#include "Server.h"
 
 
Server::Server(void)
{
}
 
 
Server::~Server(void)
{
}
 
 
bool Server::Bind(LPCSTR _ip , const UINT &_port, const int &_count_client){
 
    BaseNet::addr.sin_family        = AF_INET;
    BaseNet::addr.sin_port          = htons( _port );
    BaseNet::addr.sin_addr.s_addr   = inet_addr( _ip );
 
 
    if( bind( BaseNet::Socket, ( const sockaddr* ) &this->addr, sizeof( BaseNet::addr ) ) == SOCKET_ERROR )
 
    {
        this->err = WSAGetLastError( );
        return false;
    }else{
        return true;
    }
 
 
}
 
bool Server::Listen(void){
 
    if ( listen( BaseNet::Socket, SOMAXCONN ) == SOCKET_ERROR )
    {
        BaseNet::err = ::WSAGetLastError( );
        return false;
    }else{
        return true;
    }
 
}
 
 
bool Server::Accept(Client &_client){
 
    SOCKET client_socket    = NULL;    
    sockaddr_in client_addr = { 0 };        
    int client_addr_size    = sizeof( client_addr );
 
    client_socket           = accept(   Socket, 
        ( sockaddr* )&client_addr, 
        &client_addr_size );
 
    if( client_socket == SOCKET_ERROR )
    {
        BaseNet::err = WSAGetLastError( );
        return false;
    }
 
    _client.SaveSocketAndSockaddr( client_socket, &client_addr );
    return true;
}
 
 
// Остановка сервера
bool Server::StopServer( void )
{
    // Закрытие сокета
    if( !BaseNet::CloseSocket( ) )
        return false;
 
    // Выгрузка Winsock
    if( !BaseNet::UnloadWinsock( ) )
        return false;
 
    return true;
}
Client.h

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#pragma once
#include "BaseNet.h"
class Client : public BaseNet
{
public:
    Client(void);
    virtual ~Client(void);
 
 
    // Подключение к серверу
        bool Connect(   LPCSTR      = "127.0.0.1",  // IP/Name сервера
                        const UINT& = 33333 );      // Порт сервера
 
        // Отключение от сервера
        bool Disconnect( void );
 
        // Метод установки сохранение сокета и структуры сетевой информации
        void SaveSocketAndSockaddr( const SOCKET&,          // Сокет
                                    const sockaddr_in* );   // Структура sockaddr_in
 
};
Client.cpp

C++ (Qt)
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 "stdafx.h"
#include "Client.h"
 
 
Client::Client(void)
{
}
 
 
Client::~Client(void)
{
}
 
// Подключение к серверу
bool Client::Connect(   LPCSTR      _ip,        // IP/Name сервера
                        const UINT  &_port )    // Порт сервера
{
 
 
    // Заполнение структуры сетевой информации о сервере
    BaseNet::addr.sin_addr.s_addr = inet_addr( _ip );
    if( INADDR_NONE == BaseNet::addr.sin_addr.s_addr )
    {
        struct hostent *h = gethostbyname( _ip );
        if( !h )
        {
            BaseNet::err = WSAGetLastError( );
            return false;
        }
        BaseNet::addr.sin_addr = *(struct in_addr *) h->h_addr_list[0];
    }
    BaseNet::addr.sin_family    = AF_INET;
    BaseNet::addr.sin_port      = htons( _port );
 
    // Соединение с сервером
    if( connect( BaseNet::Socket, ( const struct sockaddr* )&this->addr, sizeof( BaseNet::addr ) ) == SOCKET_ERROR )
    {
        BaseNet::err = WSAGetLastError( );
        return false;
    }
    
    return true;
}
 
        
// Отключение от сервера
bool Client::Disconnect( void )
{
    // Закрытие сокета
    if( !BaseNet::CloseSocket( ) )
        return false;
 
    // Выгрузка Winsock
    if( !BaseNet::UnloadWinsock( ) )
        return false;
    
    return true;
}
 
// Метод установки сохранение сокета и структуры сетевой информации
void Client::SaveSocketAndSockaddr( const SOCKET        &_socket,   // Сокет
                                    const sockaddr_in   *_paddr )   // Структура sockaddr_in
{
    BaseNet::Socket = _socket;
    memcpy_s( &this->addr, sizeof( sockaddr_in ), _paddr, sizeof( sockaddr_in ) );
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
25.08.2014, 16:18
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Сокеты: после вызова send программа зависает на функции recv (C++):

После вызова рекурсивной функции программа перестаёт работать - C++
int mat,size,x=1,y, a=0, b=1; void mtt(int mat, int a, int b); int main(){ cin&gt;&gt;size; mtt(mat,a,b); cout&lt;&lt;&quot;JJ&quot;;//НЕ...

оформить решение в виде функции следующими способами: 1. функция расположена после ее вызова; 2. функция расположена после до ее вызова; 3. функ - C++
оформить решение в виде функции следующими способами: 1. функция расположена после ее вызова; 2. функция расположена после до ее...

Сокеты, функция send - C++
для того чтобы отправить сообщение , могу ли я считать символы сроки таким образом: gets(buff); send(my_sock,&amp;buff,nsize,0); Или же...

MPI зависает на Recv - C++
Вот код: int _tmain(int argc, char* argv ) { int myrank, ranksize, i; MPI_Status status; MPI_Init(&amp;argc,...

Глобальная переменная после вызова функции меняет значение - C++
До flag = 0; odnorod_pril(buffer1); После int odnorod_pril(char *buffer) { flag точно равен 1, проверял в памяти и просто...

нужно чтобы функция располагалась до ее вызова, после ее вызова и в другом файле. Как это сделать? - C++
#include &lt;iostream&gt; #include &lt;conio.h&gt; using namespace std; int n, *c; void fun(int a, int b) { for (int i = 0; i &lt;...

21
HighPredator
5545 / 1858 / 346
Регистрация: 10.12.2010
Сообщений: 5,446
Записей в блоге: 2
25.08.2014, 16:29 #2
Порт может быть закрыт, файерволлом например.
0
aLarman
643 / 564 / 89
Регистрация: 13.12.2012
Сообщений: 2,109
Завершенные тесты: 1
25.08.2014, 16:36 #3
Цитата Сообщение от mh-coder Посмотреть сообщение
не двигается с места, немогу понять почему
быть может потому что recv блокирующий вызов, и если нечего читать, то программа ждет появления данных
0
mh-coder
-4 / 26 / 3
Регистрация: 01.02.2014
Сообщений: 813
25.08.2014, 16:45  [ТС] #4
Цитата Сообщение от HighPredator Посмотреть сообщение
Порт может быть закрыт, файерволлом например.
в первый раз же работает, как он может быть закрыт
Цитата Сообщение от aLarman Посмотреть сообщение
быть может потому что recv блокирующий вызов, и если нечего читать, то программа ждет появления данных
в смысле ничего не читать? я даже если еще раз открываю любую страничку в браузере, тоесть отправляю данные то ничего не происходит, браузер ждёт ожидания ответа от сервера, а recv постоянно возвращает самый первый результат
0
aLarman
643 / 564 / 89
Регистрация: 13.12.2012
Сообщений: 2,109
Завершенные тесты: 1
25.08.2014, 16:48 #5
Цитата Сообщение от mh-coder Посмотреть сообщение
в смысле ничего не читать
нЕчего читать
0
mh-coder
-4 / 26 / 3
Регистрация: 01.02.2014
Сообщений: 813
25.08.2014, 17:33  [ТС] #6
Цитата Сообщение от aLarman Посмотреть сообщение
нЕчего читать
омг, а как может быть такое что нечего читать если я всётаки открываю страницу в браузере и по идее должны передаватся заголовки??
0
aLarman
643 / 564 / 89
Регистрация: 13.12.2012
Сообщений: 2,109
Завершенные тесты: 1
25.08.2014, 17:41 #7
Цитата Сообщение от mh-coder Посмотреть сообщение
а как может быть такое что нечего читать если я всётаки открываю страницу в браузере и по идее должны передаватся заголовки??
ну если recv висит то читать нечего.....
0
mh-coder
-4 / 26 / 3
Регистрация: 01.02.2014
Сообщений: 813
25.08.2014, 17:53  [ТС] #8
Цитата Сообщение от aLarman Посмотреть сообщение
ну если recv висит то читать нечего.....
ну так я и спрашиваю почему нечего, ведь по логике так быть недолжно
0
Убежденный
Ушел с форума
Эксперт С++
15708 / 7219 / 1139
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
25.08.2014, 22:25 #9
Цитата Сообщение от mh-coder
C++
1
2
3
4
5
6
7
8
9
10
b.Bind("127.0.0.1",2222,SOMAXCONN);
b.Listen();
b.Accept(c);
 
while(true){
    c.RecvData(data,1000);  
 
    //  c.SendData(data,1000);
    cout<<c.GetError()<<"\n"<<data<<"\n";
}
Цитата Сообщение от mh-coder Посмотреть сообщение
1) после использования функции send - код зависает над функцией recv и не двигается с места, немогу понять почему
А чего вы ждали ?
RecvData читает данные из клиентского сокета и SendData тут же пытается отправить
их обратно. Для клиента это выглядит так, как будто сервер выполнил "эхо-ответ".
Для HTTP это, мягко говоря, странно. Про то, что здесь даже не проверяется количество
принятых байт, как и вообще ошибки, я вообще молчу.

Цитата Сообщение от mh-coder Посмотреть сообщение
2) если убрать send то всё работает нормально, но recv постоянно возвращает заголовки отправлнные в первый раз не реагируя на те сайты которые открываются в браузере в дальнёйшем.
Браузер может создавать десятки и сотни подключений.
В данном коде только один Accept.
1
mh-coder
-4 / 26 / 3
Регистрация: 01.02.2014
Сообщений: 813
26.08.2014, 00:45  [ТС] #10
Убежденный, я короче поместил Accept в цыкл и всё заработало, насчёт эхо ответа, я просто хотел проверить как оно работает ну и ненашол ничего другова что можно отправить)) а зачем проверять количество принятых байт?
0
aLarman
643 / 564 / 89
Регистрация: 13.12.2012
Сообщений: 2,109
Завершенные тесты: 1
26.08.2014, 09:07 #11
Цитата Сообщение от mh-coder Посмотреть сообщение
а зачем проверять количество принятых байт
в recv Вы указываете сколько желаете прочитать, но recv может прочитать меньше, например, Вы ждете 512 байт, а на сокет пришло только 300, так же recv может вернуть управление программе и прочитать 0 байт, там уже смотреть надо на код ошибки(errno - linux, WSAGetLastError() - windows)
собвственно что получется, Вы передаете например 512 байт, кусками по 100 байт, т.е сначала вычитаем 100, потом еще 100, и еще 3 раза по 100, и в последний раз вычитаем 12....вот надо смотреть сколько прочитали, что бы склеить результат, или понять что мы все дочитали....или если не все, выполнить чтение еще необходимое кол-во раз
2
mh-coder
-4 / 26 / 3
Регистрация: 01.02.2014
Сообщений: 813
27.08.2014, 17:53  [ТС] #12
Цитата Сообщение от aLarman Посмотреть сообщение
или понять что мы все дочитали....или если не все, выполнить чтение еще необходимое кол-во раз
а как узнать сколько всего данных должно придти? чтобы понять всё дочитал или не всё
0
aLarman
643 / 564 / 89
Регистрация: 13.12.2012
Сообщений: 2,109
Завершенные тесты: 1
27.08.2014, 22:59 #13
1ый вариант, знать это априори
2) в конце последовательности иметь уникальную посл.байт, что бы понять что все пришло

Добавлено через 33 секунды
3) в передаваемой посл.байт отвести байт задающий длину последовательности
0
mh-coder
-4 / 26 / 3
Регистрация: 01.02.2014
Сообщений: 813
28.08.2014, 18:50  [ТС] #14
Столкнулся со следующей проблемой, несрабатывает функция дисконект, тоесть браузер уже получил все заголовки и html код, но серовно остаётся в стадии загрузки страницы, как ему дат понять что уже всё загрузилось и пора отключатся?



C++ (Qt)
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
#include "stdafx.h"
#include "Header.h"
#include "Server.h"
 
 
 
int _tmain(int argc, _TCHAR* argv[])
{
 
 
 
    char data[10240] = {NULL};
 
    Client c;
    Client c2;
    Server b;
    b.LoadWinsoсk();
    b.CreateSocket();
 
    c.LoadWinsoсk();
    c.CreateSocket();
 
    c2.LoadWinsoсk();
    c2.CreateSocket();
 
    b.Bind("127.0.0.1",2222,SOMAXCONN);
    b.Listen();
    
    Array ex;
    string url;
 
    while(true){
        b.Accept(c);
        c.RecvData(data,1024);  
 
        ex = explode("\r\n",data);
        url = str_replace("Host: ","",ex[1] );
        //тут получаем домен
 
 
        c2.Connect(url.c_str(),80);
        cout<<c.GetError()<<"\n"<<"\n";
        c2.SendData(data,c.GetRecvSize());
        cout<<c.GetError()<<"\n"<<"\n";
 
        while(true)
        {
        c2.RecvData(data,10240);
        if(c2.GetRecvSize() == 0 ){
        break;  
        }
        c.SendData(data,c2.GetRecvSize());
        memset(data,0,sizeof(data));
        }
        cout<<c.GetError()<<"\n"<<data<<"\n";
        
        c.Disconnect();
       c2.Disconnect();
    }
 
    return 0;
}
0
Убежденный
Ушел с форума
Эксперт С++
15708 / 7219 / 1139
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
28.08.2014, 22:30 #15
Цитата Сообщение от mh-coder Посмотреть сообщение
как ему дат понять что уже всё загрузилось и пора отключатся?
shutdown function
http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx
0
28.08.2014, 22:30
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
28.08.2014, 22:30
Привет! Вот еще темы с ответами:

Каким будет значение переменной k после вызова функции f в main: - C++
void f(int &amp;a) { a++; } int main() { int k = 0; f(k); }

Зависает программа после ввода массива - C++
Помогите найти ошибку, программа ищет и выводит на экран два максимальных элемента всех нечетных строк массива: #include &lt;iostream.h&gt; ...

Обработка функции recv структуры SOCKET - C++
Прошу помощи как обработать полученную информацию из функции recv структуры SOCKET. к примеру: char buf=&quot;GooD&quot;;char mass; retVal...

Как избавиться от остановки программы из-за функции recv()? - C++
Я пишу чат на WinSock. Суть его проста - существует цикл, в котором идет такая последовательность действий: 1. Если нажат Enter, то...


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

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

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