#c
Вопрос:
Я получаю пакеты по upd и создаю структуру PSG. Затем я сохраняю его в вектор и сортирую.В конце я записываю все байтовые данные в файл. Проблема в том, что последний пакет составляет менее 1424 байт. и из-за этого в конец файла записываются дополнительные байты. Как я могу правильно сохранить данные из recvfrom()
структуры, чтобы избежать лишних байтов?
#pragma pack(push, 1)
struct PSG
{
uint64_t id;
uint64_t size;
uint32_t type;
uint32_t count;
uint8_t data[1400];
};
#pragma pack(pop)
PSG psg;
std::vector<PSG> psg_vector;
while(1) {
if ((bytesrecv = recvfrom(m_sock, amp;psg, 1424, 0, (sockaddr *) NULL, NULL)) < 0) {
perror("recvfrom");
close(m_sock);
return -1;
}
psg_vector.push_back(psg);
sort(psg_vector.begin(), psg_vector.end(), [](const auto amp;lhs, const
auto amp;rhs) {
return lhs.count < rhs.count;
});
for (auto amp;a: psg_vector) {
file.write(reinterpret_cast<const char *>(amp;a.data), sizeof(a.data));
}
}
Комментарии:
1. Может быть , использовать что-то другое, чем
sizeof(a.data)
, можетPSG::count
быть ?2. Вместо передачи sizeof(a.данные) в файл. write(), вычислите фактическое количество байтов, которые вы хотите записать, и передайте их.
3. с справочной страницы:
recvfrom
возвращает «…количество полученных байтов или -1, если произошла ошибка. Возвращаемое значение будет равно 0, когда одноранговый узел выполнит упорядоченное завершение работы.». Используетсяbytesrecv
для проверки ошибок и определения количества байтов для записи в файл.
Ответ №1:
Вы получаете размер считанного пакета bytesrecv
, но затем игнорируете его и не используете его. Храните его где-нибудь и используйте. Вы можете добавить его в свой объект PSG:
#pragma pack(push, 1)
struct PSG
{
uint64_t id;
uint64_t size;
uint32_t type;
uint32_t count;
uint8_t data[1400];
ssize_t size;
};
#pragma pack(pop)
PSG psg;
std::vector<PSG> psg_vector;
while(1) {
if ((psg.size = recvfrom(m_sock, amp;psg, 1424, 0, (sockaddr *) NULL, NULL)) < 0) {
perror("recvfrom");
close(m_sock);
return -1;
}
psg_vector.push_back(psg);
Ответ №2:
Пример на сокетах linux. Вам нужны эти строки:
if (!length) // Write entire buffer
fileManager.WriteFile(data->buffer, BUFF_LENGTH);
else // Write remain
{
fileManager.WriteFile(data->buffer, length);
break;
}
Полный пример:
struct Packet
{
enum class TYPE
{
DEFAULT = 3, // Default condition
LAST_OF_FILE = 4, // Last packet of file
N_LAST_OF_FILE = 5, // Not last packet of file
LAST_IN_GROUP = 6, // Last file in group of files, sent by client
N_LAST_IN_GROUP = 7, // Not last file in group of files, sent by client
ANSWER = 8 // Answer
};
uint32_t length;
TYPE type;
char buffer[BUFF_LENGTH];
void clear()
{
memset(this, 0, sizeof(Packet));
}
};
bool ReceiveOnePacket(Packet* pack, int* socket)
{
// summary quantity of received bytes
uint32_t bytes = 0;
while (bytes < sizeof(Packet))
{
// a tcp socket cannot give the entire packet as a whole, so we read it in parts.
// We read with a shift and reduce the number of remaining bytes
int len = recv(*socket, ((char*)pack) bytes, sizeof(Packet) - bytes, 0);
if (len <= 0)
return false;
bytes = len;
}
return true;
}
void ReceivingFiles(std::shared_ptr<int> socket, std::shared_ptr<Packet> data)
{
data->clear();
bool isLastFile = false;
while (!isLastFile) // Receiving set of files
{
// receiving filename of current file
if (!ReceiveOnePacket(data.get(), socket.get()))
{
close(*socket);
return;
}
// if current file is last then data->packetType == Packet::TYPE::LAST_IN_GROUP,
// if file not last, data->packetType == Packet::TYPE::N_LAST_IN_GROUP
isLastFile = data->type == Packet::TYPE::LAST_IN_GROUP;
std::string metaData(data->buffer, data->length);
fileManager.OpenFile(metaData);
// Receiving one File
while (true)
{
if (!ReceiveOnePacket(data.get(), socket.get()))
{
fileManager.DeleteFile();
close(*socket);
return;
}
uint32_t length = data->length;
if (!length) // Write entire buffer
fileManager.WriteFile(data->buffer, BUFF_LENGTH);
else // Write remain
{
fileManager.WriteFile(data->buffer, length);
break;
}
} // End Receiving one file
}
}