Здравствуйте, -Cheese-, Вы писали:
C>Здравствуйте, CrystaX, Вы писали:
CX>>Это какие-то части сообщений тоже. TCP не добавляет никаких маркеров. Это поток в чистом виде и ничего более. Ты уверен, что там именно 2, а не 4 байта, обозначающих размер? C>когда не слеиваются, то точно 2 байта
CX>>Кроме того, какое представление целочисленных величин используется (какой byte-order)? C>Чего?
Здравствуйте, CrystaX, Вы писали:
CX>Поищи тогда здесь или в MSDN-е. Ключевые слова: network byte order, host byte order.
прочитал. вроде понял.
не понял к чему это...
может я не правильно изьяснился в начале.
проблема в следующем:
пакет, который мне приходит имеет след. структуру —
2 байта (число N) + N байт
где N — длина сообщения
т.е. пакеты вида
x1mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
x2mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
x3mmmmmmmmmmmmm
но при большом потоке запросов мне приходит сообщение вида
x1mmmmmmmmmmmmmmmmmmmmmmx2mmmmmmmmmmmmmmmmmmmmx3mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
где
x1 — длина всего сообщения
x2 — длина второго сообщения
x3 — длина третьего сообщения
Внимание, вопрос:
как мне узнать где начинается x2,x3?
Здравствуйте, -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 байт. И т.д.
Здравствуйте, CrystaX, Вы писали:
CX>Ничего не понимаю. Ну прочитал ты первые два байта (x1). Теперь ты знаешь длину первого сообщения. CX>Считываешь x1 байт. Следующие два байта — это уже число x2. Считываешь x2 байт. И т.д.
в том то и дело, что х1 — не длина первого сообщения, а длина всего склеенного сообщения!
CX>Я, может, чего-то не понимаю?
Здравствуйте, -Cheese-, Вы писали:
C>Здравствуйте, CrystaX, Вы писали:
CX>>Ничего не понимаю. Ну прочитал ты первые два байта (x1). Теперь ты знаешь длину первого сообщения. CX>>Считываешь x1 байт. Следующие два байта — это уже число x2. Считываешь x2 байт. И т.д. C>в том то и дело, что х1 — не длина первого сообщения, а длина всего склеенного сообщения!
То есть это особенность протокола такая? Если да, то никак тебе помочь не могу, не зная протокола. Скажи хоть тогда, что за протокол, а то иначе гадание на кофейной гуще получается
Здравствуйте, CrystaX, Вы писали:
CX>То есть это особенность протокола такая? Если да, то никак тебе помочь не могу, не зная протокола. Скажи хоть тогда, что за протокол, а то иначе гадание на кофейной гуще получается
TCP\IP
самый обнаковенный... просто вот такая фигня получается со склейкой...
может это глюк?
часто повторяющийся...
Здравствуйте, -Cheese-, Вы писали:
C>Здравствуйте, CrystaX, Вы писали:
CX>>То есть это особенность протокола такая? Если да, то никак тебе помочь не могу, не зная протокола. Скажи хоть тогда, что за протокол, а то иначе гадание на кофейной гуще получается
C>TCP\IP C>самый обнаковенный... просто вот такая фигня получается со склейкой...
Ты не понял. Я имел в виду высокоуровневый протокол. TCP — это транспортный протокол.
C>может это глюк? C>часто повторяющийся...
Здравствуйте, CrystaX, Вы писали:
CX> C>>TCP\IP C>>самый обнаковенный... просто вот такая фигня получается со склейкой... CX>Ты не понял. Я имел в виду высокоуровневый протокол. TCP — это транспортный протокол.
ну я ещё не волшебник.... только учусь C>>может это глюк? C>>часто повторяющийся...
CX>Очень вряд ли. Скорее всего у тебя баг.
ну будем смотреть.
Здравствуйте, -Cheese-, Вы писали:
C>Здравствуйте, CrystaX, Вы писали:
CX>> C>>>TCP\IP C>>>самый обнаковенный... просто вот такая фигня получается со склейкой... CX>>Ты не понял. Я имел в виду высокоуровневый протокол. TCP — это транспортный протокол. C>ну я ещё не волшебник.... только учусь C>>>может это глюк? C>>>часто повторяющийся...
CX>>Очень вряд ли. Скорее всего у тебя баг. C>ну будем смотреть.
C>всё равно спасибо за потраченное время!
Приведи минимальный код, на котором проявляется ошибка. Думается, баг будет быстро найден.
Здравствуйте, 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 workif (select(maxfd + 1, &readfds, NULL, &exfds, &tv) == -1) break;
// On exception in server socket also breaks immediatelyif(FD_ISSET(ssocket, &exfds)) break;
// Test events on client socketsfor (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);
/////////////////
}
отдельный процесс время от времени читает стек и отвечает на запросы.
Здравствуйте, -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>отдельный процесс время от времени читает стек и отвечает на запросы.
Здравствуйте, 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;
}
Здравствуйте, -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 проверка числа, находящегося в первых двух байтах?
Здравствуйте, CrystaX, Вы писали:
CX>Ок, понял. И где в твоей process_data проверка числа, находящегося в первых двух байтах?
так вот в этом-то и проблема.
я не знаю как обрабатывать полученное сообщение (если оно склеенное).
Делал так: повторил ситуацию, получил эту склейку (в режиме отладки исследовал её), смотрю и не знаю как её побороть..
Здравствуйте, -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) == 2short 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;
}
CX> // Тут нужно особое внимание обратить на byte order. Если у тебя архитектура little-endian, CX> // а значение высылается в сетевом порядке байт, то ntohs обязательна CX> // short здесь в предположении что sizeof(short) == 2
приложение будет запускаться на 2000 винде
компилятор VC++
Здравствуйте, -Cheese-, Вы писали:
C>Здравствуйте, CrystaX, Вы писали:
C>бррррр C>а для чего ещё раз?
Смотри:
Первые два Оставшаяся часть
байта сообщения
| |
+--------+------------------------+
| xx xx | xx xx xx xx xx xx |
+--------+------------------------+
Чтобы узнать длину сообщения, нужно сначала прочитать первые два байта. Это первое чтение. Затем, зная длину — оставшуюся часть. Это второе чтение.
А цикл — это как раз гарантия того, что данные будут получены полностью, без потерь, причем столько, сколько нужно.
C>