Re[12]: TCP IP очередь запросов...
От: CrystaX Россия https://crystax.me/
Дата: 20.05.05 09:21
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Здравствуйте, CrystaX, Вы писали:


CX>>Это какие-то части сообщений тоже. TCP не добавляет никаких маркеров. Это поток в чистом виде и ничего более. Ты уверен, что там именно 2, а не 4 байта, обозначающих размер?

C>когда не слеиваются, то точно 2 байта

CX>>Кроме того, какое представление целочисленных величин используется (какой byte-order)?

C>Чего?

О htons, ntohs что-нибудь слышал?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[13]: TCP IP очередь запросов...
От: -Cheese-  
Дата: 20.05.05 10:59
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>О htons, ntohs что-нибудь слышал?

нет
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Re[14]: TCP IP очередь запросов...
От: CrystaX Россия https://crystax.me/
Дата: 20.05.05 11:08
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Здравствуйте, CrystaX, Вы писали:


CX>>О htons, ntohs что-нибудь слышал?

C>нет

Поищи тогда здесь или в MSDN-е. Ключевые слова: network byte order, host byte order.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[15]: TCP IP очередь запросов...
От: -Cheese-  
Дата: 20.05.05 11:33
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>Поищи тогда здесь или в MSDN-е. Ключевые слова: network byte order, host byte order.

прочитал. вроде понял.
не понял к чему это...

может я не правильно изьяснился в начале.
проблема в следующем:
пакет, который мне приходит имеет след. структуру —
2 байта (число N) + N байт
где N — длина сообщения

т.е. пакеты вида
x1mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
x2mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
x3mmmmmmmmmmmmm

но при большом потоке запросов мне приходит сообщение вида
x1mmmmmmmmmmmmmmmmmmmmmmx2mmmmmmmmmmmmmmmmmmmmx3mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm

где
x1 — длина всего сообщения
x2 — длина второго сообщения
x3 — длина третьего сообщения

Внимание, вопрос:
как мне узнать где начинается x2,x3?
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Re[16]: TCP IP очередь запросов...
От: CrystaX Россия https://crystax.me/
Дата: 20.05.05 11:40
Оценка: +1
Здравствуйте, -Cheese-, Вы писали:

C>Здравствуйте, CrystaX, Вы писали:


CX>>Поищи тогда здесь или в MSDN-е. Ключевые слова: network byte order, host byte order.

C>прочитал. вроде понял.
C>не понял к чему это...

C>может я не правильно изьяснился в начале.

C>проблема в следующем:
C>пакет, который мне приходит имеет след. структуру —
C>2 байта (число N) + N байт
C>где N — длина сообщения

C>т.е. пакеты вида

C>x1mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
C>x2mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
C>x3mmmmmmmmmmmmm

C>но при большом потоке запросов мне приходит сообщение вида

C>x1mmmmmmmmmmmmmmmmmmmmmmx2mmmmmmmmmmmmmmmmmmmmx3mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm

C>где

C>x1 — длина всего сообщения
C>x2 — длина второго сообщения
C>x3 — длина третьего сообщения

C>Внимание, вопрос:

C> как мне узнать где начинается x2,x3?

Ничего не понимаю. Ну прочитал ты первые два байта (x1). Теперь ты знаешь длину первого сообщения. Считываешь x1 байт. Следующие два байта — это уже число x2. Считываешь x2 байт. И т.д.

Я, может, чего-то не понимаю?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[17]: TCP IP очередь запросов...
От: -Cheese-  
Дата: 20.05.05 11:55
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>Ничего не понимаю. Ну прочитал ты первые два байта (x1). Теперь ты знаешь длину первого сообщения.

CX>Считываешь x1 байт. Следующие два байта — это уже число x2. Считываешь x2 байт. И т.д.
в том то и дело, что х1 — не длина первого сообщения, а длина всего склеенного сообщения!

CX>Я, может, чего-то не понимаю?
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Re[18]: TCP IP очередь запросов...
От: CrystaX Россия https://crystax.me/
Дата: 20.05.05 12:03
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Здравствуйте, CrystaX, Вы писали:


CX>>Ничего не понимаю. Ну прочитал ты первые два байта (x1). Теперь ты знаешь длину первого сообщения.

CX>>Считываешь x1 байт. Следующие два байта — это уже число x2. Считываешь x2 байт. И т.д.
C>в том то и дело, что х1 — не длина первого сообщения, а длина всего склеенного сообщения!

То есть это особенность протокола такая? Если да, то никак тебе помочь не могу, не зная протокола. Скажи хоть тогда, что за протокол, а то иначе гадание на кофейной гуще получается
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[19]: TCP IP очередь запросов...
От: -Cheese-  
Дата: 20.05.05 12:10
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>То есть это особенность протокола такая? Если да, то никак тебе помочь не могу, не зная протокола. Скажи хоть тогда, что за протокол, а то иначе гадание на кофейной гуще получается


TCP\IP
самый обнаковенный... просто вот такая фигня получается со склейкой...
может это глюк?
часто повторяющийся...
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Re[20]: TCP IP очередь запросов...
От: CrystaX Россия https://crystax.me/
Дата: 20.05.05 12:13
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Здравствуйте, CrystaX, Вы писали:


CX>>То есть это особенность протокола такая? Если да, то никак тебе помочь не могу, не зная протокола. Скажи хоть тогда, что за протокол, а то иначе гадание на кофейной гуще получается


C>TCP\IP

C>самый обнаковенный... просто вот такая фигня получается со склейкой...

Ты не понял. Я имел в виду высокоуровневый протокол. TCP — это транспортный протокол.

C>может это глюк?

C>часто повторяющийся...

Очень вряд ли. Скорее всего у тебя баг.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[21]: TCP IP очередь запросов...
От: -Cheese-  
Дата: 20.05.05 12:18
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>

C>>TCP\IP
C>>самый обнаковенный... просто вот такая фигня получается со склейкой...
CX>Ты не понял. Я имел в виду высокоуровневый протокол. TCP — это транспортный протокол.
ну я ещё не волшебник.... только учусь
C>>может это глюк?
C>>часто повторяющийся...

CX>Очень вряд ли. Скорее всего у тебя баг.

ну будем смотреть.

всё равно спасибо за потраченное время!
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Re[22]: TCP IP очередь запросов...
От: CrystaX Россия https://crystax.me/
Дата: 20.05.05 12:22
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Здравствуйте, CrystaX, Вы писали:


CX>>

C>>>TCP\IP
C>>>самый обнаковенный... просто вот такая фигня получается со склейкой...
CX>>Ты не понял. Я имел в виду высокоуровневый протокол. TCP — это транспортный протокол.
C>ну я ещё не волшебник.... только учусь
C>>>может это глюк?
C>>>часто повторяющийся...

CX>>Очень вряд ли. Скорее всего у тебя баг.

C>ну будем смотреть.

C>всё равно спасибо за потраченное время!


Приведи минимальный код, на котором проявляется ошибка. Думается, баг будет быстро найден.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[23]: TCP IP очередь запросов...
От: -Cheese-  
Дата: 20.05.05 12:37
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>Приведи минимальный код, на котором проявляется ошибка. Думается, баг будет быстро найден.

я бы не назвал это ошибкой... просто мне приходит сообщение описанного выше вида...

в основе как я говорил берклиевский классический сервер.
(взял где-то в инете и чуть модифицировал)


bool process_data(SOCKET sock)
{
    /////////////////
        if ((received = recv(sock, buf, RECVBUFSIZ, 0)) != SOCKET_ERROR && received>2) {
      // здесь вот buf может являться тем злополучным сообщением (а может и не быть им).
      buf[received] = '\0';
            pushToStack(buf,received); // тут просто парсером прогоняю сообщение и кладу в стек сообщений
            return true;
    }
    return false;
}

/////////////////////////////////////////////////////////////////////////////
UINT ListenSockets(LPVOID lpvoid)
{
    while (true) {
            ///////////
        if ((accepted = accept(ssocket, (struct sockaddr *) &ca, (socklen_t *)&cal)) != SOCKET_ERROR){
                    int size=sizeof(sockaddr);
                    sockaddr_in adr;
                    int ret=getpeername(accepted,(sockaddr*)&adr,&size);
                    if(adr.sin_addr.S_un.S_addr==IP_CLIENT){
                if(clients.size()==0){
                    sprintf(buffer,"Client connected [%s]",inet_ntoa(adr.sin_addr));
                    clients.push_back(accepted);
                }else{
                    sprintf(buffer,"Client already connected [%s]. Ignored",inet_ntoa(adr.sin_addr));
                    shutdown_socket(&accepted);
                }
            }else{
                sprintf(buffer,"Illegal client want to connect [%s]",inet_ntoa(adr.sin_addr));
                shutdown_socket(&accepted);
            }
            toLog(buffer);
        }
        
        // Preparing descriptor sets
        FD_ZERO(&readfds);
        FD_ZERO(&exfds);
        FD_SET(ssocket, &exfds);
        tv.tv_sec = 1;
        tv.tv_usec = 0;
        maxfd = ssocket;

        for (CL::iterator ii = clients.begin(); ii != clients.end(); ++ii) {
            FD_SET((SOCKET )*ii, &readfds);
            FD_SET((SOCKET )*ii, &exfds);
            maxfd = max(maxfd, (SOCKET )*ii);
        }
    
        // select failing breaks the work
        if (select(maxfd + 1, &readfds, NULL, &exfds, &tv) == -1) break;
        
         // On exception in server socket also breaks immediately
        if(FD_ISSET(ssocket, &exfds)) break;
    
        // Test events on client sockets
        for (ii = clients.begin(); ii != clients.end(); ++ii) {
            if (FD_ISSET(*ii, &exfds)) {
                                toLog("Client exception");
                if (*ii != INVALID_SOCKET) shutdown_socket(&(*ii));
                if ((ii = clients.erase(ii)) == clients.end()) break;
            }
            if (FD_ISSET(*ii, &readfds) && !process_data(*ii)) {
                                toLog("Failed to read client");
                if (*ii != INVALID_SOCKET) shutdown_socket(&(*ii));
                if ((ii = clients.erase(ii)) == clients.end()) break;
            }
        }
    }
    for (CL::iterator ii = clients.begin(); ii != clients.end(); ++ii) {
        if (*ii != INVALID_SOCKET) shutdown_socket(&(*ii));
        if ((ii = clients.erase(ii)) == clients.end()) break;
    }
    /////////////////
  shutdown_socket(&ssocket);
    /////////////////
}



отдельный процесс время от времени читает стек и отвечает на запросы.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Re[24]: TCP IP очередь запросов...
От: CrystaX Россия https://crystax.me/
Дата: 20.05.05 12:53
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Здравствуйте, CrystaX, Вы писали:


CX>>Приведи минимальный код, на котором проявляется ошибка. Думается, баг будет быстро найден.

C>я бы не назвал это ошибкой... просто мне приходит сообщение описанного выше вида...

C>в основе как я говорил берклиевский классический сервер.

C>(взял где-то в инете и чуть модифицировал)

C>
C>bool process_data(SOCKET sock)
C>{
C>    /////////////////
C>        if ((received = recv(sock, buf, RECVBUFSIZ, 0)) != SOCKET_ERROR && received>2) {
C>      // здесь вот buf может являться тем злополучным сообщением (а может и не быть им).
C>      buf[received] = '\0';
C>            pushToStack(buf,received); // тут просто парсером прогоняю сообщение и кладу в стек сообщений
C>            return true;
C>    }
C>    return false;
C>}
C>


Вот здесь неверно. Тебе никто не гарантирует, что данные будут приходить кусками, не меньшими чем 2 или еще сколько байт. Теоретически возможна ситуация, когда данные вообще могут приходить по одному байту за одно чтение. В этом случае ты их потеряешь.

Не факт, конечно, что это и единственный баг, но это точно надо исправить. Насчет же следующей функции (ListenSockets) — извини, не понял, что она должна делать. Никаких данных ты в ней не читаешь, так откуда же они берутся?

C>
C>/////////////////////////////////////////////////////////////////////////////
C>UINT ListenSockets(LPVOID lpvoid)
C>{
C>    while (true) {
C>            ///////////
C>        if ((accepted = accept(ssocket, (struct sockaddr *) &ca, (socklen_t *)&cal)) != SOCKET_ERROR){
C>                    int size=sizeof(sockaddr);
C>                    sockaddr_in adr;
C>                    int ret=getpeername(accepted,(sockaddr*)&adr,&size);
C>                    if(adr.sin_addr.S_un.S_addr==IP_CLIENT){
C>                if(clients.size()==0){
C>                    sprintf(buffer,"Client connected [%s]",inet_ntoa(adr.sin_addr));
C>                    clients.push_back(accepted);
C>                }else{
C>                    sprintf(buffer,"Client already connected [%s]. Ignored",inet_ntoa(adr.sin_addr));
C>                    shutdown_socket(&accepted);
C>                }
C>            }else{
C>                sprintf(buffer,"Illegal client want to connect [%s]",inet_ntoa(adr.sin_addr));
C>                shutdown_socket(&accepted);
C>            }
C>            toLog(buffer);
C>        }
        
C>        // Preparing descriptor sets
C>        FD_ZERO(&readfds);
C>        FD_ZERO(&exfds);
C>        FD_SET(ssocket, &exfds);
C>        tv.tv_sec = 1;
C>        tv.tv_usec = 0;
C>        maxfd = ssocket;

C>        for (CL::iterator ii = clients.begin(); ii != clients.end(); ++ii) {
C>            FD_SET((SOCKET )*ii, &readfds);
C>            FD_SET((SOCKET )*ii, &exfds);
C>            maxfd = max(maxfd, (SOCKET )*ii);
C>        }
    
C>        // select failing breaks the work
C>        if (select(maxfd + 1, &readfds, NULL, &exfds, &tv) == -1) break;
        
C>         // On exception in server socket also breaks immediately
C>        if(FD_ISSET(ssocket, &exfds)) break;
    
C>        // Test events on client sockets
C>        for (ii = clients.begin(); ii != clients.end(); ++ii) {
C>            if (FD_ISSET(*ii, &exfds)) {
C>                                toLog("Client exception");
C>                if (*ii != INVALID_SOCKET) shutdown_socket(&(*ii));
C>                if ((ii = clients.erase(ii)) == clients.end()) break;
C>            }
C>            if (FD_ISSET(*ii, &readfds) && !process_data(*ii)) {
C>                                toLog("Failed to read client");
C>                if (*ii != INVALID_SOCKET) shutdown_socket(&(*ii));
C>                if ((ii = clients.erase(ii)) == clients.end()) break;
C>            }
C>        }
C>    }
C>    for (CL::iterator ii = clients.begin(); ii != clients.end(); ++ii) {
C>        if (*ii != INVALID_SOCKET) shutdown_socket(&(*ii));
C>        if ((ii = clients.erase(ii)) == clients.end()) break;
C>    }
C>    /////////////////
C>  shutdown_socket(&ssocket);
C>    /////////////////
C>}
C>



C>отдельный процесс время от времени читает стек и отвечает на запросы.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[25]: TCP IP очередь запросов...
От: -Cheese-  
Дата: 20.05.05 13:00
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>Вот здесь неверно. Тебе никто не гарантирует, что данные будут приходить кусками, не меньшими чем 2 или еще сколько байт. Теоретически возможна ситуация, когда данные вообще могут приходить по одному байту за одно чтение. В этом случае ты их потеряешь.


я думаю такого не случится.
сервера стоят рядом на одном хабе.

CX>Не факт, конечно, что это и единственный баг, но это точно надо исправить. Насчет же следующей функции (ListenSockets) — извини, не понял, что она должна делать. Никаких данных ты в ней не читаешь, так откуда же они берутся?

как не читаю...

            if (FD_ISSET(*ii, &readfds) && !process_data(*ii)) {
                                toLog("Failed to read client");
                if (*ii != INVALID_SOCKET) shutdown_socket(&(*ii));
                if ((ii = clients.erase(ii)) == clients.end()) break;
            }
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Re[26]: TCP IP очередь запросов...
От: CrystaX Россия https://crystax.me/
Дата: 20.05.05 13:07
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Здравствуйте, CrystaX, Вы писали:


CX>>Вот здесь неверно. Тебе никто не гарантирует, что данные будут приходить кусками, не меньшими чем 2 или еще сколько байт. Теоретически возможна ситуация, когда данные вообще могут приходить по одному байту за одно чтение. В этом случае ты их потеряешь.


C>я думаю такого не случится.

C>сервера стоят рядом на одном хабе.

Это ничего не значит. Если на принимающей стороне переполнится буфер TCP, то эта ситуация возможна. А ты сам говоришь, что данные идут с высокой частотой.

CX>>Не факт, конечно, что это и единственный баг, но это точно надо исправить. Насчет же следующей функции (ListenSockets) — извини, не понял, что она должна делать. Никаких данных ты в ней не читаешь, так откуда же они берутся?

C>как не читаю...

C>
C>            if (FD_ISSET(*ii, &readfds) && !process_data(*ii)) {
C>                                toLog("Failed to read client");
C>                if (*ii != INVALID_SOCKET) shutdown_socket(&(*ii));
C>                if ((ii = clients.erase(ii)) == clients.end()) break;
C>            }
C>


Ок, понял. И где в твоей process_data проверка числа, находящегося в первых двух байтах?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[27]: TCP IP очередь запросов...
От: -Cheese-  
Дата: 20.05.05 13:18
Оценка:
Здравствуйте, CrystaX, Вы писали:

CX>Ок, понял. И где в твоей process_data проверка числа, находящегося в первых двух байтах?

так вот в этом-то и проблема.
я не знаю как обрабатывать полученное сообщение (если оно склеенное).
Делал так: повторил ситуацию, получил эту склейку (в режиме отладки исследовал её), смотрю и не знаю как её побороть..
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Re[28]: TCP IP очередь запросов...
От: CrystaX Россия https://crystax.me/
Дата: 20.05.05 13:41
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Здравствуйте, CrystaX, Вы писали:


CX>>Ок, понял. И где в твоей process_data проверка числа, находящегося в первых двух байтах?

C>так вот в этом-то и проблема.
C>я не знаю как обрабатывать полученное сообщение (если оно склеенное).
C>Делал так: повторил ситуацию, получил эту склейку (в режиме отладки исследовал её), смотрю и не знаю как её побороть..

Нет, не так. Вот примерный код, как это должно выглядеть:
bool process_data(SOCKET sock)
{
    int received = 0, required = 2;
    while((received = recv(sock, buf + received, required - received, 0)) > 0);
    if(received == SOCKET_ERROR) return false;

    // Тут нужно особое внимание обратить на byte order. Если у тебя архитектура little-endian,
    // а значение высылается в сетевом порядке байт, то ntohs обязательна
    // short здесь в предположении что sizeof(short) == 2
    short size = ntohs(*reinterpret_cast<short *>(buf));
    
    required = size;
    received = 0;
    while((received = recv(sock, buf + received, required - received, 0)) > 0);
    if(received == SOCKET_ERROR) return false;
    
    buf[size] = '\0';
    pushToStack(buf, size);
    return true;
}
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[29]: TCP IP очередь запросов...
От: -Cheese-  
Дата: 20.05.05 13:54
Оценка:
Здравствуйте, CrystaX, Вы писали:

бррррр
а для чего ещё раз?

bool process_data(SOCKET sock)
{
    int received = 0, required = 2;
    while((received = recv(sock, buf + received, required - received, 0)) > 0);
    if(received == SOCKET_ERROR) return false;
    short size = ntohs(*reinterpret_cast<short *>(buf));
    
    required = size;
    received = 0;
    
        
        while((received = recv(sock, buf + received, required - received, 0)) > 0);
    if(received == SOCKET_ERROR) return false;
    
    
        buf[size] = '\0';
    pushToStack(buf, size);
    return true;
}
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Re[29]: TCP IP очередь запросов...
От: -Cheese-  
Дата: 20.05.05 14:00
Оценка:
CX> // Тут нужно особое внимание обратить на byte order. Если у тебя архитектура little-endian,
CX> // а значение высылается в сетевом порядке байт, то ntohs обязательна
CX> // short здесь в предположении что sizeof(short) == 2

приложение будет запускаться на 2000 винде
компилятор VC++
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Re[30]: TCP IP очередь запросов...
От: CrystaX Россия https://crystax.me/
Дата: 20.05.05 14:01
Оценка:
Здравствуйте, -Cheese-, Вы писали:

C>Здравствуйте, CrystaX, Вы писали:


C>бррррр

C>а для чего ещё раз?

Смотри:
Первые два    Оставшаяся часть
байта             сообщения
    |                 |
+--------+------------------------+
| xx  xx | xx  xx  xx  xx  xx  xx |
+--------+------------------------+


Чтобы узнать длину сообщения, нужно сначала прочитать первые два байта. Это первое чтение. Затем, зная длину — оставшуюся часть. Это второе чтение.
А цикл — это как раз гарантия того, что данные будут получены полностью, без потерь, причем столько, сколько нужно.

C>
C>bool process_data(SOCKET sock)
C>{
C>    int received = 0, required = 2;
C>    while((received = recv(sock, buf + received, required - received, 0)) > 0);
C>    if(received == SOCKET_ERROR) return false;
C>    short size = ntohs(*reinterpret_cast<short *>(buf));
    
C>    required = size;
C>    received = 0;
    
C>        
C>        while((received = recv(sock, buf + received, required - received, 0)) > 0);
C>    if(received == SOCKET_ERROR) return false;
C>    
    
C>        buf[size] = '\0';
C>    pushToStack(buf, size);
C>    return true;
C>}

C>
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.