Я работаю над реализацией протокола "остановись и работай" с использованием UDP.Я по существу использую буфер символов для сериализации любых данных, которые я посылаю, используя ntoh и hton, где это необходимо, и десериализацию, как только мои данные достигают другой стороны.Все отлично работает, однако, когда я пытаюсь отправить файл, я получаю случайные фиктивные байты в новом файле.Я попытаюсь обобщить необходимую информацию для этого вопроса:
Первый символ в моем буфере символов представляет тип отправляемого пакета.Я установил небольшое трехстороннее рукопожатие для установления соединения.Сервер просто принимает определенный порт в качестве аргумента, клиент берет IP-адрес, порт и имя файла, а затем запрашивает этот файл с сервера.Сервер отвечает размером файла, а затем клиент отправляет окончательный пакет ACK, после чего данные отправляются.Я использую fread () для отправки данных ~ 1 КБ за раз, используя размер буфера 1 КБ.Как только клиент получает этот пакет, он отправляет пакет подтверждения, а затем ожидает следующий пакет данных.Вот соответствующий код:
else if (b == 'a')
{
memcpy(&dacpkt.seqNum, buffer+sizeof(char), sizeof(int));
dacpkt.seqNum = ntohl(dacpkt.seqNum); // convert from network to host data
datapkt.pktLen = 1017;
if (dacpkt.seqNum == datapkt.seqNum)
{
++seq;
dacpkt.t = b;
datapkt.seqNum = seq;
fread(datapkt.data, datapkt.pktLen, 1, filereq);
memcpy(buffer, &datapkt.t, sizeof(char)); // data packet type
off = sizeof(char);
datapkt.seqNum = htonl(datapkt.seqNum);
memcpy(buffer + off, &datapkt.seqNum, sizeof(int)); // data packet sequence#
off += sizeof(int);
datapkt.pktLen = htons(datapkt.pktLen);
memcpy(buffer + off, &datapkt.pktLen, sizeof(short)); // data packet size
off += sizeof(short);
memcpy(buffer + off, &datapkt.data, 1017); // data packet payload
n = sendto(sock, buffer, MAX, 0, (struct sockaddr*) &from, fromlen);
if (n < 0)
error("sendto");
}
if(fread(datapkt.data, 1017, 1, filereq) != 1017) // fread hit the end of the file
{
++seq;
dacpkt.t = 'c';
dacpkt.seqNum = seq;
memcpy(buffer, &dacpkt.t, sizeof(char)); // close packet
off = sizeof(char);
dacpkt.seqNum = htonl(dacpkt.seqNum);
memcpy(buffer + off, &dacpkt.seqNum, sizeof(int)); // close packet sequence#
n = sendto(sock, buffer, 5, 0, (struct sockaddr*) &from, fromlen);
}
}
dacpkt - это пакет подтверждения, который я заполняю при десериализации буфера символов из recvfrom (), а datapkt - это пакет, который я строю, затем сериализую и отправляю.Я СЧИТАЮ, что моя проблема в моем использовании фреда.Вот код получения на стороне клиента:
if (b == 'd')
{
//build the response packet and send
memset(buffer, 0, MAX);
//populate struct
dacpkt.t = 'a';
dacpkt.seqNum = htonl(sequence_num);
//copy to buffer
memcpy(buffer, &dacpkt.t, sizeof(char));
off = sizeof(char);
memcpy(buffer + off, &dacpkt.seqNum, sizeof(int));
//send the ACK
n = sendto(sock, buffer, MAX, 0, (struct sockaddr *) &server, length);
if (n < 0)
error("sendto");
//receive as well before exiting while loop
memset(buffer, 0, MAX);
n = recvfrom(sock, buffer, MAX, 0, (struct sockaddr *) &from, &length);
if (n < 0)
error("recvfrom");
datapkt.t = buffer[0];
off = sizeof(char);
memcpy(&datapkt.seqNum, buffer + off, sizeof(int));
datapkt.seqNum = ntohl(datapkt.seqNum);
off += sizeof(int);
memcpy(&datapkt.pktLen, buffer + off, sizeof(short));
datapkt.pktLen = ntohl(datapkt.pktLen);
off += sizeof(short);
strcat(datapkt.data, buffer + off);
//ensures we are receiving the next packet
if (datapkt.seqNum = (sequence_num + 1))
{
n = fputs(datapkt.data, newfile); //we need buffer to be the exact size
if (n < 0)
error("writing to file");
sequence_num = datapkt.seqNum;
}
}
fclose(newfile);
}
//post-receiving the file!
memset(buffer, 0, MAX);
dacpkt.t = 'c';
dacpkt.seqNum = htonl(sequence_num);
memcpy(buffer, &dacpkt.t, sizeof(char));
memcpy(buffer + 1, &dacpkt.seqNum, sizeof(int));
//send the ACK
n = sendto(sock, buffer, MAX, 0, (struct sockaddr *) &server, length);
if (n < 0)
error("sendto");
Извините, если информация, которую я предоставил, немного неоднозначна, но я вполне уверен, что мои проблемы заключаются в чтении / записи в файл.Например, я запустил программу, пытаясь передать текстовый файл с алфавитными символами (az) в каждой строке, на 600 строк.Исходный файл имел размер 16200 байт, а новый файл, созданный отправляющими данными, - всего 3069 байт.Новый файл содержит всего 113 строк, и случайные байты появляются повсюду так:
36 abcdefghijklmnopqrstuvwxyz
37 abcdefghijklmnopqrstuvwxyz
38 abcdefghijklmnopqr8ze$ü^?abcdefghijklmnopqrstuvwxyz
39 abcdefghijklmnopqrstuvwxyz
и, в частности, в конце файла:
111 abcdefghijklmnopqrstuvwxyz
112 abcdefghijklmnopqrstuvwxyz
113 abcdefghi8ze$ü^?
Я думаю, что я не понимаюкак работает fread () в отношении того, как определить, когда закончить передачу файла.Если у кого-то есть идеи о том, как я мог бы реализовать это лучше, я весь в ушах.Все, что я хочу сделать, это отправлять данные по одному килобайтному пакету за раз, пока я не достигну конца файла, после чего я отправляю этот окончательный частичный пакет, а затем отправляю сигнал на закрытие клиента.