Не могу "скопировать" содержимое переменной

Модератор: Модераторы разделов

Ответить
Аватара пользователя
denel
Сообщения: 497
ОС: Gentoo Linux
Контактная информация:

Не могу "скопировать" содержимое переменной

Сообщение denel »

Пытаюсь переносить содержимое socked_reply в pkg[pkgNum]

Код: Выделить всё

  pkg[pkgNum] = socked_reply; // 4
Но вижу, что каждый раз после перезаписи содержимого socked_reply меняется и содержимое старых, ранее присвоенных pkg[pkgNum], на новое. Определяю так:

Код: Выделить всё

if(pkg[10] != 0 && pkg[10] == pkg[pkgNum]) std::cout << "!!!!!!!!!!" << pkgNum << std::endl;
Вот весь код. Прошу сильно не пинать, с таким глубоким "познанием" имею дело впервые.

Код: Выделить всё

#include <iostream>
#include <string.h>     //strlen
#include <sys/socket.h>
#include <arpa/inet.h>  //inet_addr

const int32_t pkgBufMax = 60000; // Число строк
const int32_t lenString = 1316; // Длина каждой строки
int32_t cacheTime = 15 * 1000000; // Время кеша в наносекундах
char *pkg[pkgBufMax] = {new char [lenString]};
long int pkgMemTime[pkgBufMax];

int main() {
        int32_t pkgSize = 1316;
        int32_t socketTCPid;
        struct sockaddr_in sockedTCP;
        char socked_reply[pkgSize] = {0};
        //Create socket
        socketTCPid = socket(AF_INET, SOCK_STREAM, 0);
        if (socketTCPid == -1)
        {
                printf("Could not create socket");
        }

        sockedTCP.sin_addr.s_addr = inet_addr("192.168.0.100");
        sockedTCP.sin_family = AF_INET;
        sockedTCP.sin_port = htons( 9999 );

        //Connect to remote server
        if (connect(socketTCPid , (struct sockaddr *)&sockedTCP, sizeof(sockedTCP)) < 0)
        {
              return 1;
        }

        char message[] = "GET / HTTP/1.0\r\nConnection: close\r\n\r\n";
        if( send(socketTCPid , message , strlen(message) , 0) < 0)
        {
              return 1;
        }
        //Receive a reply from the server
        int32_t readed = 0;
        bool acceptSend = 0;
        int32_t pkgNum = 0;
        while (1) {
          readed = recv(socketTCPid, socked_reply, pkgSize, 0);
          if (readed < 0) {
          } else {
            if (acceptSend == 1) {
              pkg[pkgNum] = socked_reply; // 4

if(pkg[10] != 0 && pkg[10] == pkg[pkgNum]) std::cout << "!!!!!!!!!!" << pkgNum << std::endl;

              std::cout << pkgMemTime[pkgNum] << " " << 0 << " " << pkgNum << " " << sizeof(socked_reply) << std::endl;
              pkgNum ++; //3
              if (pkgNum == pkgBufMax) pkgNum = 0;
            }
          }
          acceptSend = 1;
        }

  return 0;
}
В чём дело - не пойму.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20790
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Не могу "скопировать" содержимое переменной

Сообщение Bizdelnick »

У Вас pkg — массив указателей на char. Вы записываете в pkg[pkgNum] указатель на начало массива, копирования данных тут нет.
И вообще код ужасен.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
denel
Сообщения: 497
ОС: Gentoo Linux
Контактная информация:

Re: Не могу "скопировать" содержимое переменной

Сообщение denel »

Bizdelnick писал:
10.02.2021 22:31
У Вас pkg — массив указателей на char. Вы записываете в pkg[pkgNum] указатель на начало массива, копирования данных тут нет.
Долгое время не мог воспользоваться

Код: Выделить всё

memcpy(pkg[pkgNum], socked_reply, pkgSize);
так как программа аварийно завершалась при попытке такого копирования. Сейчас это удалось поправить следующим образом:

Код: Выделить всё

// Изменил изначальную инициализацию pkg
char *pkg[pkgBufMax] = {new char [lenString]};
// на
char *pkg[pkgBufMax];
и далее перед циклом добавил, как я понимаю, выделение динамической памяти:

Код: Выделить всё

while (pkgNum < pkgBufMax)
{
  pkg[pkgNum] = new char [pkgSize];
  pkgNum ++;
}
В результате код получился примерно такой:

Код: Выделить всё

#include <iostream>
#include <string.h>     //strlen
#include <sys/socket.h>
#include <arpa/inet.h>  //inet_addr

const int32_t pkgBufMax = 60000; // Число строк
const int32_t pkgSize = 1316; // Длина каждой строки
char *pkg[pkgBufMax];// = {new char [pkgSize]};

int main() {
        int32_t socketTCPid;
        struct sockaddr_in sockedTCP;
        char socked_reply[pkgSize] = {0};
        //Create socket
        socketTCPid = socket(AF_INET, SOCK_STREAM, 0);
        if (socketTCPid == -1)
        {
          std::cerr << "Ошибка создания сокета TCP. Выход" << std::endl;
          return 1;
        }

        sockedTCP.sin_addr.s_addr = inet_addr("192.168.0.100");
        sockedTCP.sin_family = AF_INET;
        sockedTCP.sin_port = htons( 9999 );

        //Connect to remote server
        if (connect(socketTCPid , (struct sockaddr *)&sockedTCP, sizeof(sockedTCP)) < 0)
        {
          std::cerr << "Ошибка CONNECT. Выход" << std::endl;
          return 1;
        }

        char message[] = "GET / HTTP/1.0\r\nConnection: close\r\n\r\n";
        if( send(socketTCPid , message , strlen(message) , 0) < 0)
        {
          std::cerr << "Ошибка SEND. Выход" << std::endl;
          return 1;
        }
        //Receive a reply from the server
        int32_t readed = 0;

        int32_t pkgNum = 0;
        while (pkgNum < pkgBufMax)
        {
          pkg[pkgNum] = new (std::nothrow) char [pkgSize];
          if (!pkg[pkgNum])
          {
            std::cerr << "Ошибка выделения памяти для pkg[" << pkgNum << "]. Выход" << std::endl;
            return 1;
          }
          pkgNum ++;
        }

        readed = recv(socketTCPid, socked_reply, pkgSize, 0);
        if (readed < 0) {
          std::cerr << "Ошибка чтения RECV. Выход" << std::endl;
          return 1;
        }

        pkgNum = 0;
        while (1) {
          memset(socked_reply , 0 , pkgSize);
          readed = recv(socketTCPid, socked_reply, pkgSize, 0);
          if (readed < 0) {
            std::cerr << "Ошибка чтения RECV. Выход" << std::endl;
            return 1;
          }
          memcpy(pkg[pkgNum], socked_reply, pkgSize);

if(pkg[10] != 0 && pkg[10] == pkg[pkgNum]) std::cout << "!!!!!!!!!!" << pkgNum << std::endl;

          pkgNum ++; //3
          if (pkgNum == pkgBufMax) pkgNum = 0;
        }

  return 0;
}
Bizdelnick писал:
10.02.2021 22:31
И вообще код ужасен.
А конкретней можно, за что глаз так резко цепляется?
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20790
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Не могу "скопировать" содержимое переменной

Сообщение Bizdelnick »

denel писал:
11.02.2021 08:05
А конкретней можно, за что глаз так резко цепляется?
Ну он цеплялся чуть ли не за каждую вторую строчку. Сейчас стало получше. Но вообще на C++ так не пишут, это же почти чистый C. В частности, если нужен именно C++, то надо вместо

Код: Выделить всё

#include <string.h>
использовать

Код: Выделить всё

#include <cstring>
по сандарту.

Потом, Вы используете тип int32_t, но не включаете заголовочный файл, в котором он определён (видимо, он включается опосредованно, но всё равно стоит указать явно). Для C это

Код: Выделить всё

#include <stdint.h>
а для C++

Код: Выделить всё

#include <cstdint>
Потом, раз уж C++, то чтобы не плясать с инициализацией массива, логично использовать std::vector. А если всё-таки C, то

Код: Выделить всё

char pkg[pkgBufMax][pkgSize];
Ещё глаз очень сильно цепляется за имя переменной "readed". Такого слова в английском языке нет, read — неправильный глагол.
Бесконечные циклы ПМСМ — зло, я бы заменил условие в while (1), в данном случае это несложно:

Код: Выделить всё

while ((read = recv(socketTCPid, socked_reply, pkgSize, 0)) >= 0)
А memset там не особо нужен, только время на него тратится.
Вероятно, что-то ещё пропустил.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
s.xbatob
Сообщения: 1139
ОС: Fedora

Re: Не могу "скопировать" содержимое переменной

Сообщение s.xbatob »

А ещё вы свято верите, что recv() (который для SOCK_STREAM ничем не отличается от простого read() ) вернёт вам сразу весь ответ целиком за один раз. В вашем случае надо читать последовательно до EOF (да ещё и таймауты как-то обрабатывать)
Спасибо сказали:
Аватара пользователя
denel
Сообщения: 497
ОС: Gentoo Linux
Контактная информация:

Re: Не могу "скопировать" содержимое переменной

Сообщение denel »

s.xbatob писал:
11.02.2021 12:34
А ещё вы свято верите, что recv() (который для SOCK_STREAM ничем не отличается от простого read() ) вернёт вам сразу весь ответ целиком за один раз. В вашем случае надо читать последовательно до EOF (да ещё и таймауты как-то обрабатывать)
Какое интересное замечание! Если Вы ещё не догадались — я читаю real-time медиапоток для последующей его переотправки в немного модифицированном виде. По-моему на данный момент читать по 1316 байт будет просто удобно, хочу добавить некоторые данные в начало отправляемого пакета вставив принятый пакет в конец отправляемого пакета. Но мысль о том, что read (recv) не прочитает сразу все данные — интересна. То есть есть некое EOF? Это случаем не \0? Если это \0 — то он присутствует в каждом пакете примерно каждые толи 8 толи 64 байт (точно сейчас не помню, но не стабильно). Если размер char это 1 байт, то ближе к 8 байт. А как ещё может быть выражен EOF в медиапакете (бинарном)? Позже я наверно даже выложу исходники того, что получилось. И для чего оно получилось :)
Спасибо сказали:
Аватара пользователя
s.xbatob
Сообщения: 1139
ОС: Fedora

Re: Не могу "скопировать" содержимое переменной

Сообщение s.xbatob »

denel
Я не разбирался что вы запрашиваете, но вижу вижу HTTP с заголовком "Connection: close" из чего предполагаю, что после получения полного ответа сервер закроет соединение, и очередной read() прочтёт 0 байт. Это и есть EOF, другого нет.
Но и это упрощение. По уму надо сразу по мере получения заголовка его разбирать, извлекать Content-Length (про retcode я вообще молчу) и дальше читать данные по счётчику.
Вы же как я вижу, что-то читаете, игнорируете это и сразу же читаете опять. Вы вообще на что надеетесь?
Впрочем, до этих граблей вам ещё далеко :(
Последний раз редактировалось s.xbatob 11.02.2021 13:35, всего редактировалось 1 раз.
Спасибо сказали:
Аватара пользователя
denel
Сообщения: 497
ОС: Gentoo Linux
Контактная информация:

Re: Не могу "скопировать" содержимое переменной

Сообщение denel »

Bizdelnick писал:
11.02.2021 12:04
Потом, раз уж C++, то чтобы не плясать с инициализацией массива, логично использовать std::vector. А если всё-таки C, то

Код: Выделить всё

char pkg[pkgBufMax][pkgSize];
Благодарю за чёткий информативный ответ! Но тут вот с массивом такая штука, что 60000*1316 — это вылазит за границу в 1МБ, то есть за рамки стека. Поэтому я 60000 элементов первого уровня массива инициализирую статически (это же вроде так называется), а потом для каждого из этих элементов динамически запрашиваю выделение по 1316 байт у ОС.
Bizdelnick писал:
11.02.2021 12:04
Ещё глаз очень сильно цепляется за имя переменной "readed". Такого слова в английском языке нет, read — неправильный глагол.
Спасибо за замечание) Я английский то не знаю, импровизирую. Иногда переменные содержат латиницей татарские, башкирские слова и даже порой матерную брань))) Но я стараюсь учиться культуре :)
Bizdelnick писал:
11.02.2021 12:04
А memset там не особо нужен, только время на него тратится.
Я это добавил на всякий случай, если вдруг пакет окажется менее 1316 байт, таким образом переменная будет перезаписана не полностью, в ней останутся старые данные. — это предположение.
Последний раз редактировалось denel 11.02.2021 13:44, всего редактировалось 1 раз.
Спасибо сказали:
Аватара пользователя
denel
Сообщения: 497
ОС: Gentoo Linux
Контактная информация:

Re: Не могу "скопировать" содержимое переменной

Сообщение denel »

s.xbatob писал:
11.02.2021 13:28
denel
Я не разбирался что вы запрашиваете, но вижу вижу HTTP с заголовком "Connection: close" из чего предполагаю, что после получения полного ответа сервер закроет соединение, и очередной read() прочтёт 0 байт. Это и есть EOF, другого нет.
Но и это упрощение. По уму надо сразу по мере получения заголовка его разбирать, извлекать Content-Length (про retcode я вообще молчу) и дальше читать данные по счётчику.
Вы же как я вижу, что-то читаете, игнорируете это и сразу же читаете опять. Вы вообще на что недеетесь?
Впрочем, до этих граблей вам ещё далеко :(
Пожалуй Вы правы. Потом будет необходимо добавить разбор первого прочитанного пакета, чтобы не подключалось к чему угодно. Но если этому создавать лабораторные условия, то есть давать подключаться только к тому, к чему надо — суть прочитанного первого пакета похоже не играет роли, главное — это то, что следует за ним — бесконечный realtime мультимедиа поток.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20790
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Не могу "скопировать" содержимое переменной

Сообщение Bizdelnick »

denel писал:
11.02.2021 13:29
Но тут вот с массивом такая штука, что 60000*1316 — это вылазит за границу в 1МБ, то есть за рамки стека.
Так у Вас статический массив (поскольку он объявлен в глобальной области видимости), а не стековый.
denel писал:
11.02.2021 13:29
Поэтому я 60000 элементов первого уровня массива инициализирую статически (это же вроде так называется)
Так я предлагаю весь массив сделать статическим.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
s.xbatob
Сообщения: 1139
ОС: Fedora

Re: Не могу "скопировать" содержимое переменной

Сообщение s.xbatob »

denel
TCP и вообще SOCK_STREAM — это не пакеты, а поток байт, разбитый на куски, причём произвольным образом! Его надо вычитывать последовательно по мере необходимости. Если лень или не хватает знаний сделать это совсем самостоятельно, то можете на fd сокета создать FILE * или std::istream. Правда я не уверен, что при работе с двоичной информацией они не будут проявлять ненужный интеллект.
Спасибо сказали:
Аватара пользователя
denel
Сообщения: 497
ОС: Gentoo Linux
Контактная информация:

Re: Не могу "скопировать" содержимое переменной

Сообщение denel »

Bizdelnick писал:
11.02.2021 13:44
denel писал:
11.02.2021 13:29
Но тут вот с массивом такая штука, что 60000*1316 — это вылазит за границу в 1МБ, то есть за рамки стека.
Так у Вас статический массив (поскольку он объявлен в глобальной области видимости), а не стековый.
denel писал:
11.02.2021 13:29
Поэтому я 60000 элементов первого уровня массива инициализирую статически (это же вроде так называется)
Так я предлагаю весь массив сделать статическим.
Какой ужас! Я изначально предполагал, что эта переменная будет глобальной, но начал её сначала инициализировать в main, поломав зубки))) Кучу времени потратил на то, чтобы воспользоваться "кучей". Потом уже, перенеся инициализацию в глобальную область, не пробовал снова объявлять многомерный массив сразу. Зато вон сколько сразу узнал)))
Высвобождение памяти в данном случае не нужно. Хотя... Может имеет смысл не объявлять второй уровень полностью, а динамически выделять память и освобождать её. Мне там нужна "история" принятых данных, но она нужна лишь для порядка 600 пакетов. 600 из 60000. Лучше же динамически выделять/освобождать? Но это будут ещё проверки перед выделением :) А если я буду объявлять массив сразу - как освобождать неиспользуемые элементы массива? Пока с этим ничего не получилось.
Спасибо сказали:
Аватара пользователя
denel
Сообщения: 497
ОС: Gentoo Linux
Контактная информация:

Re: Не могу "скопировать" содержимое переменной

Сообщение denel »

s.xbatob писал:
11.02.2021 13:46
denel
TCP и вообще SOCK_STREAM — это не пакеты, а поток байт, разбитый на куски, причём произвольным образом! Его надо вычитывать последовательно по мере необходимости.
В данный момент, когда цикл доходит до recv, он ожидает, когда поступит 1316 байт данных и только после этого продолжается выполнение цикла. Сейчас вместо этого указал 1416 байт и на удивление VLC ему начал отправлять по 1416 байт, судя по tcpdump. Интересный вопрос, конечно, как это происходит.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20790
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Не могу "скопировать" содержимое переменной

Сообщение Bizdelnick »

denel писал:
11.02.2021 14:46
Лучше же динамически выделять/освобождать?
Это зависит. Если память будет использоваться в любом случае, её выделение и освобождение в куче — просто лишняя трата ресурсов. Память не экономите, время теряете.
denel писал:
11.02.2021 14:46
А если я буду объявлять массив сразу - как освобождать неиспользуемые элементы массива?
Никак. Вы же сами пишете, что
denel писал:
11.02.2021 14:46
Высвобождение памяти в данном случае не нужно.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Ответить