1 条题解
-
0
自动搬运
来自洛谷,原作者为

MrPython
waac_tXKCMem1dAph0gg0搬运于
2025-08-24 22:57:05,当前版本为作者最后更新于2024-04-10 12:03:16,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
既然是工程题,那就尽量让程序良构起来吧!
我们按照手册所说定义两个结构体:
struct pcap_hdr { // 所有字段都是大端序 uint32_t magic_number;// 用于文件类型识别,始终为 0xA1B2C3D4, uint16_t version_major;// 始终为 2 uint16_t version_minor;// 始终为 4 int32_t thiszone;// 始终为 0 uint32_t sigfigs;// 始终为 0 uint32_t snaplen;// 允许的最大包长度,始终为 262144 uint32_t network;// 数据类型,本次学习题中始终为 1 (以太网) } __attribute__ ((packed)); struct pcaprec_hdr{ // 所有字段都是大端序 uint32_t ts_sec;// 时间戳(秒) uint32_t ts_usec;// 时间戳(微秒) uint32_t incl_len;// 该片段的存储长度 uint32_t orig_len;// 该片段实际的长度 } __attribute__ ((packed));其中
__attribute__ ((packed))是为了避免因内存对齐导致中间出现神秘空位,输入失败。我们再将对结构体的输入输出方法定义好:
friend std::istream& pcap_hdr::operator>>(std::istream& in,pcap_hdr& data){ in.read((char*)&data,sizeof(pcap_hdr)); data.magic_number=ntohl(data.magic_number), data.version_major=ntohs(data.version_major), data.version_minor=ntohs(data.version_minor), data.thiszone=ntohl(data.thiszone), data.sigfigs=ntohl(data.sigfigs), data.snaplen=ntohl(data.snaplen), data.network=ntohl(data.network); assert(data.magic_number==0xA1B2C3D4&& // 输入错误导致 RE,方便调试 data.version_major==2&& data.version_minor==4&& data.thiszone==0&& data.sigfigs==0&& data.snaplen==262144&& data.network==1 ); return in; } friend std::ostream& operator<<(std::ostream& out,pcap_hdr data){ data.magic_number=htonl(data.magic_number), data.version_major=htons(data.version_major), data.version_minor=htons(data.version_minor), data.thiszone=htonl(data.thiszone), data.sigfigs=htonl(data.sigfigs), data.snaplen=htonl(data.snaplen), data.network=htonl(data.network); out.write((char*)&data,sizeof(pcap_hdr)); return out; } friend std::istream& pcaprec_hdr::operator>>(std::istream& in,pcaprec_hdr& data){ in.read((char*)&data,sizeof(pcaprec_hdr)); data.ts_sec=ntohl(data.ts_sec), data.ts_usec=ntohl(data.ts_usec), data.incl_len=ntohl(data.incl_len), data.orig_len=ntohl(data.orig_len); assert(data.ts_usec<1e6&&data.incl_len==data.orig_len); return in; } friend std::ostream& operator<<(std::ostream& out,pcaprec_hdr data){ data.incl_len=htonl(data.incl_len), data.orig_len=htonl(data.orig_len), data.ts_sec=htonl(data.ts_sec), data.ts_usec=htonl(data.ts_usec); out.write((char*)&data,sizeof(pcaprec_hdr)); return out; }这里,我使用
std::basic_istream::read直接将流内的二进制数据写入结构体中,std::basic_ostream::write将结构体的内容写入流。两个函数都接受一个const char*和一个整数,分别表示要写/读的内存地址和要操作的字节数。将指向结构体的类型强制转换,与结构体大小一起传入即可。ntohlntohshtonlhtons定义在netinet/in.h。ntohlntohs分别将 32 位/16 位大端序整数转换为本机使用的端序,htonlhtons分别将 32 位/16 位本机使用的端序转换为大端序。在输入输出操作前,需要使用这些函数处理端序问题。为了好玩我还定义了两个辅助结构体,分别将报文与文件进行封装。struct pcaprec{ pcaprec_hdr header; std::vector<uint8_t> data; pcaprec():header(),data(){} friend std::istream& operator>>(std::istream& in,pcaprec& data){ in>>data.header; data.data.resize(data.header.orig_len); in.read(data.data.data(),data.header.orig_len); return in; } friend std::ostream& operator<<(std::ostream& out,pcaprec const& data){ out<<data.header; out.write((char*)data.data.data(),data.header.incl_len); return out; } }; struct pcap{ pcap_hdr header; std::vector<pcaprec> data; pcap():header(),data(){} friend std::istream& operator>>(std::istream& in,pcap& data){ in>>data.header; while (!in.eof()) data.data.push_back([](std::istream& in){ pcaprec p;in>>p;return p; }(in)); data.data.pop_back(); return in; } friend std::ostream& operator<<(std::ostream& out,pcap const& data){ out<<data.header; for (pcaprec const& i:data.data) out<<i; return out; } }; struct pcap{ pcap_hdr header; std::vector<pcaprec> data; pcap():header(),data(){} friend std::istream& operator>>(std::istream& in,pcap& data){ in>>data.header; while (!in.eof()) data.data.push_back([](std::istream& in){ pcaprec p;in>>p;return p; }(in)); data.data.pop_back(); // cin 读取到 eof 后总还要多读一位,只能 pop 掉了 return in; } friend std::ostream& operator<<(std::ostream& out,pcap const& data){ out<<data.header; for (pcaprec const& i:data.data) out<<i; return out; } };做完了这些准备工作,main 函数的内容就相当简单了。
附上我的代码:
#ifndef ONLINE_JUDGE std::ifstream fin("./data/P10344.in",std::ifstream::binary); std::ofstream fout("./data/P10344.out",std::ofstream::binary); #else std::istream& fin=std::cin; std::ostream& fout=std::cout; #endif struct pcap_hdr { // 所有字段都是大端序 uint32_t magic_number;// 用于文件类型识别,始终为 0xA1B2C3D4, uint16_t version_major;// 始终为 2 uint16_t version_minor;// 始终为 4 int32_t thiszone;// 始终为 0 uint32_t sigfigs;// 始终为 0 uint32_t snaplen;// 允许的最大包长度,始终为 262144 uint32_t network;// 数据类型,本次学习题中始终为 1 (以太网) friend std::istream& operator>>(std::istream& in,pcap_hdr& data){ in.read((char*)&data,sizeof(pcap_hdr)); data.magic_number=ntohl(data.magic_number), data.version_major=ntohs(data.version_major), data.version_minor=ntohs(data.version_minor), data.thiszone=ntohl(data.thiszone), data.sigfigs=ntohl(data.sigfigs), data.snaplen=ntohl(data.snaplen), data.network=ntohl(data.network); assert(data.magic_number==0xA1B2C3D4&& data.version_major==2&& data.version_minor==4&& data.thiszone==0&& data.sigfigs==0&& data.snaplen==262144&& data.network==1 ); return in; } friend std::ostream& operator<<(std::ostream& out,pcap_hdr data){ data.magic_number=htonl(data.magic_number), data.version_major=htons(data.version_major), data.version_minor=htons(data.version_minor), data.thiszone=htonl(data.thiszone), data.sigfigs=htonl(data.sigfigs), data.snaplen=htonl(data.snaplen), data.network=htonl(data.network); out.write((char*)&data,sizeof(pcap_hdr)); return out; } } __attribute__ ((packed)); struct pcaprec_hdr{ // 所有字段都是大端序 uint32_t ts_sec;// 时间戳(秒) uint32_t ts_usec;// 时间戳(微秒) uint32_t incl_len;// 该片段的存储长度 uint32_t orig_len;// 该片段实际的长度 friend std::istream& operator>>(std::istream& in,pcaprec_hdr& data){ in.read((char*)&data,sizeof(pcaprec_hdr)); data.ts_sec=ntohl(data.ts_sec), data.ts_usec=ntohl(data.ts_usec), data.incl_len=ntohl(data.incl_len), data.orig_len=ntohl(data.orig_len); assert(data.ts_usec<1e6&&data.incl_len==data.orig_len); return in; } friend std::ostream& operator<<(std::ostream& out,pcaprec_hdr data){ data.incl_len=htonl(data.incl_len), data.orig_len=htonl(data.orig_len), data.ts_sec=htonl(data.ts_sec), data.ts_usec=htonl(data.ts_usec); out.write((char*)&data,sizeof(pcaprec_hdr)); return out; } } __attribute__ ((packed)); struct pcaprec{ pcaprec_hdr header; std::vector<uint8_t> data; pcaprec():header(),data(){} friend std::istream& operator>>(std::istream& in,pcaprec& data){ in>>data.header; data.data.resize(data.header.orig_len); in.read((char*)data.data.data(),data.header.orig_len); return in; } friend std::ostream& operator<<(std::ostream& out,pcaprec const& data){ out<<data.header; out.write((char*)data.data.data(),data.header.incl_len); return out; } }; struct pcap{ pcap_hdr header; std::vector<pcaprec> data; pcap():header(),data(){} friend std::istream& operator>>(std::istream& in,pcap& data){ in>>data.header; while (!in.eof()) data.data.push_back([](std::istream& in){ pcaprec p;in>>p;return p; }(in)); data.data.pop_back(); return in; } friend std::ostream& operator<<(std::ostream& out,pcap const& data){ out<<data.header; for (pcaprec const& i:data.data) out<<i; return out; } }; int main(void){ std::ios::sync_with_stdio(false),std::cin.tie(nullptr),std::cout.tie(nullptr); pcap f;fin>>f; pcap nf; nf.header=f.header; for (auto i:f.data) if (i.header.orig_len<=1000) nf.data.push_back(i); sort(nf.data.begin(),nf.data.end(), [](pcaprec const& a,pcaprec const& b){ return (a.header.ts_sec)*(uint64_t)1e6+a.header.ts_usec <(b.header.ts_sec)*(uint64_t)1e6+b.header.ts_usec; } ); fout<<nf; return 0; }由于 某些原因,我希望大家可以保持学术诚信,自己完成这道题目。作为回报,你的码力将会有所提升。
- 1
信息
- ID
- 10042
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者