Отправка большой строки Base64 через сокет TCP - PullRequest
1 голос
/ 21 октября 2019

Я пытаюсь отправить закодированное с помощью Base64 изображение с TCP-клиента, используя GO и TCP-сервер на C ++.

Вот фрагмент кода для C ++ Receiver

std::string recieve(int bufferSize=1024,const char *eom_flag = "<EOF>"){
char buffer[bufferSize];
std::string output;
int iResult;
char *eom;
do{
    iResult = recv(client, buffer, sizeof(buffer), 0);
    //If End OF MESSAGE flag is found.
    eom = strstr(buffer,eom_flag);
    //If socket is waiting , do dot append the json, keep on waiting.
    if(iResult == 0){
        continue;
    }
    output+=buffer;
    //Erase null character, if exist.
    output.erase(std::find(output.begin(), output.end(), '\0'), output.end());
        //is socket connection is broken or end of message is reached.
}while(iResult > -1 and eom == NULL);
//Trim <EOF>
std::size_t eom_pos = output.rfind(eom_flag);
return output.substr(0,eom_pos);}

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

Фрагмент кода клиента Golang TCP.

//Making connection
connection, _ := net.Dial("tcp", "localhost"+":"+PortNumber)
if _, err := fmt.Fprintf(connection, B64img+"<EOF>"); err != nil {
            log.Println(err)
            panic(err)
        }

Пробные подходы:

  • Увеличение размера буфера в приемнике C ++.
  • Удаление нулевого символа из конца строки в приемнике C ++.

Замечания:

  • Длина строки, отправляемой клиентом, фиксирована, а длина строки после функции приема больше и случайна. Пример: длина строки клиента Go составляет 25243. Для той же строки длина после получения при запуске отправки и получения в цикле составляет 25243, 26743, 53092, 41389, 42849.

  • Вкл. Сохраняя полученную строку в файле, я вижу символ <0x7f> <0x02> в строке.

Я использую winsock2.h для сокета c ++.

1 Ответ

2 голосов
/ 21 октября 2019

Вы обрабатываете полученные данные как строку C - последовательность байтов, заканчивающуюся байтом 0 - что неверно.

recv получает несколько байтов и помещает их в buffer. Допустим, он получил 200 байтов.

Затем вы делаете strstr(buffer,eom_flag);. strstr не знает, что было получено 200 байт. strstr начинается с начала буфера и продолжает поиск, пока не найдет ни один, или 0 байт. Есть вероятность, что он может найти в других 824 байтах буфера, даже если вы его не получили.

Тогда вы делаете output += buffer;. Это также обрабатывает буфер, как если бы он заканчивался байтом 0. Это позволит просмотреть весь буфер (не только первые 200 байтов), чтобы найти 0 байт. Затем он добавит все до этого момента в output. Опять же, он может найти 0 байтов в последних 824 байтах буфера и добавить слишком много данных. Возможно, он вообще не найдет 0 байт в буфере, а затем продолжит добавлять дополнительные данные из других переменных, которые хранятся рядом с buffer в памяти. Или он может найти 0 байтов в первых 200 байтах и ​​остановиться на этом (но только если вы отправили 0 байтов).


Что вам следует сделать, это обратить внимание на количество полученных байтов (iResult) и добавьте столько байтов к выводу. Вы можете использовать:

output.insert(output.end(), buffer, buffer+iResult);

Также (как отметил Филипп Томасиньи в комментарии), "" может быть получено не сразу. Вы можете получить "" отдельно. Вам следует проверить, есть ли у output "", вместо того, чтобы проверять, есть ли у buffer "". (Последствия этого для исполнения оставлены читателю в качестве упражнения)


Кстати, эта строка в настоящий момент ничего не делает:

output.erase(std::find(output.begin(), output.end(), '\0'), output.end());

, потому что '\ 0 'никогда не добавляется к output, потому что с output += buffer;,' \ 0 'указывает, где прекратить добавление.

...