当前位置: 首页 > news >正文

廉洁常德网站新电商平台如何推广

廉洁常德网站,新电商平台如何推广,wordpress主题后门,房价走势最新消息2022CS 144 Lab Five -- the network interface TCP报文的数据传输方式地址解析协议 ARPARP攻击科普 Network Interface 具体实现测试tcp_ip_ethernet.ccTCPOverIPv4OverEthernetAdapterTCPOverIPv4OverEthernetSpongeSocket通信过程 对应课程视频: 【计算机网络】 斯坦福大学CS144… CS 144 Lab Five -- the network interface TCP报文的数据传输方式地址解析协议 ARPARP攻击科普 Network Interface 具体实现测试tcp_ip_ethernet.ccTCPOverIPv4OverEthernetAdapterTCPOverIPv4OverEthernetSpongeSocket通信过程 对应课程视频: 【计算机网络】 斯坦福大学CS144课程 Lab Five 对应的PDF: Lab Checkpoint 4: down the stack (the network interface) TCP报文的数据传输方式 TCP报文有三种方式可被传送至远程服务器分别是 TCP-in-UDP-in-IP用户提供 TCP 包之后可以使用 Linux 提供的接口让内核来负责构造 UDP 报头、IP报头以及以太网报头并将构造出的数据包发送至下一个层。因为这一切都是内核完成的任务因此内核可以确保每个套接字都具有本地地址与端口以及远程地址与端口的唯一组合同时能保证不同进程之间的隔离。 TCP-in-IP通常TCP数据包是直接放进 IP 包作为其 payload这也因此被称为 TCP/IP。但用户层如果想直接操作构造 IP 报文的话需要使用到 Linux 提供的 TUN 虚拟网络设备来作为中转。当用户将 IP 报文发送给 TUN 设备后剩余的以太网报头构造、发送以太网帧等等的操作均会由内核自动进行无需用户干预。 这一个正是之前 Lab4 中 CS144 所使用的机制感兴趣可以仔细读读代码。 TCP-in-IP-in-Ethernet上面两种方式仍然依赖Linux内核来实现的协议栈操作。每次用户向TUN设备写入IP数据报时Linux 内核都必须构造一个适当的链路层(以太网)帧并将IP数据报作为其 payload。因此 Linux 必须找出下一跳的以太网目的地址给出下一跳的IP地址。如果 Linux 无法得知该映射关系则将会发出广播探测请求以查找到下一跳的地址等信息。而这种功能是由网络接口 network interface 也被称为适配器两者等价所实现它将会把待出口的 IP 报文转换成链路层以太网帧等等之后将链路层帧发送给 TAP 虚拟网络设备剩下的发送操作将会由它来代为完成。 比较熟悉的网络接口分别是 eth0, eth1, whan0 等等。 网络接口的大部分工作是为每个下一跳IP地址查找(和缓存)以太网地址。而这种协议被称为地址解析协议ARP。 本实验中我们将会完成一个这样的网络接口实现。 地址解析协议 ARP 在编写代码前我们需要简单的了解一下 ARP 协议。 主机或路由器不具有链路层地址而是它们的适配器即网络接口具有链路层地址。链路层地址通常称为 MAC 地址。当某个适配器要向某些目的适配器发送一个帧时发送适配器将目的适配器的 MAC 地址插入至该帧中并将该帧发送到局域网上。一块适配器可能因为广播操作接收到了一个并非向它寻址的帧因此当适配器接收到一个帧时将检查并丢弃帧的目的MAC地址不与自己MAC地址匹配的以太网帧。 为什么适配器除了有网络层地址(IP地址)以外还会有链路层地址(MAC地址)呢有两个原因 局域网是为了任意网络层协议而设计并非只用于 IP 和因特网。如果适配器使用 IP地址而不使用 MAC 地址那么每次适配器移动或重启时均需重新配置地址。 由于适配器同时拥有网络层和链路层地址因此需要相互转化。而这种转换的任务就由 地址解析协议 来完成。ARP 类似于 DNS 服务但不同的是DNS 为任何地方的主机来解析主机名但 ARP 只能为在同一个子网上的主机和路由器接口解析 IP 地址。 每台主机或路由器在其内存中保存了一张 ARP 表该表包含了 IP 地址到 MAC 地址的映射关系同时还包含了一个寿命值TTL用以表示从表中删除每个映射的时间例如 IP 地址MAC 地址TTL222.222.222.221aa-bb-cc-dd-ee-ff13:45:00222.222.222.22311-22-33-44-55-664:34:12……… 若 ARP 表中已经存放了目标 IP 地址的 MAC 地址映射那么适配器将会很容易的找出目标 MAC 地址并构造一个以太网帧。但如果找不到那么发送方将会构造一个 ARP 分组的特殊分组。 ARP 分组中的字段包括发送和接收 IP 地址以及 MAC 地址同时 ARP 查询分组和响应分组都具有相同的格式。ARP 查询分组的目的是询问子网上所有其他主机和路由器以确定对应于要解析的 IP 地址的那个 MAC 地址。 当发送适配器需要查询目的适配器的 MAC 地址时发送适配器会设置分组的目的地址为 MAC 广播地址FF-FF-FF-FF-FF-FF这样做的目的是为了让所有子网上的其他适配器都接收到。当其他适配器接收到了该 ARP 查询分组后只有 IP 匹配的适配器才会返回一个 ARP 响应分组之后发送适配器便可更新自己的 ARP 表并开始发送 IP 报文。 查询ARP报文是在广播帧中发送而响应ARP报文只在一个标准帧中发送。同时 ARP 表是自动建立的无需人为设置。若主机与子网断开连接那么该节点留在其他节点的 ARP 表中对应的条目也会被自动删除。 与之相对的ARP欺骗攻击可以利用 ARP 协议不提供对网络上的 ARP 回复进行身份验证 这样的一个缺陷来轻易执行中间人攻击或者 DOS 攻击。 其他详细信息可以看看 RFC826 规范。 ARP攻击科普 ARP欺骗攻击也称为ARP缓存投毒或ARP欺骗是利用ARP协议的漏洞进行攻击的一种方式。ARP协议本身并不提供对网络上的ARP回复进行身份验证这导致了一些安全漏洞使得攻击者可以伪造ARP响应欺骗其他网络设备并引发中间人攻击Man-in-the-MiddleMITM或者拒绝服务Denial of ServiceDoS攻击。 在ARP欺骗攻击中攻击者发送虚假的ARP响应消息给网络中的其他设备欺骗它们将正确的IP地址与错误的MAC地址相对应。这样当其他设备尝试与目标设备通信时数据包实际上会被发送到攻击者控制的设备而不是真正的目标设备。 中间人攻击的情况下攻击者可以拦截、修改或监视数据包并将其转发给目标设备使得目标设备和通信设备之间的通信看似正常但实际上所有数据都经过了攻击者的处理。这可能导致敏感信息泄露或篡改通信内容。拒绝服务攻击的情况下攻击者可能发送大量虚假的ARP响应导致目标设备的ARP缓存被混乱无法正确地将IP地址映射到MAC地址从而使得目标设备无法正常与其他设备进行通信导致网络服务中断。 为了防止ARP欺骗攻击可以采取一些防御措施例如使用静态ARP条目、启用ARP防火墙、使用网络层加密等措施以提高网络的安全性并减少攻击的风险。网络管理员和设备用户应该时刻关注网络的安全并采取必要的措施来保护网络免受潜在的攻击威胁。 Network Interface 具体实现 首先 我们需要额外设置三个数据结构分别是 _arp_tableARP 表用以查询 IP至MAC地址的映射同时还保存当前 ARP 条目的 TTL。 //! ARP 条目struct ARP_Entry {EthernetAddress eth_addr;size_t ttl;};//! ARP 表std::mapuint32_t, ARP_Entry _arp_table{};ARP条目 TTL 为 30s。 // 默认 ARP 条目过期时间 30sconst size_t _arp_entry_default_ttl 30 * 1000;_waiting_arp_response_ip_addr已经发送了的 ARP 报文。必须确保每个 ARP 报文在5秒内不重复发送。 //! 正在查询的 ARP 报文。如果发送了 ARP 请求后在过期时间内没有返回响应则丢弃等待的 IP 报文std::mapuint32_t, size_t _waiting_arp_response_ip_addr{};// 默认 ARP 请求过期时间 5sconst size_t _arp_response_default_ttl 5 * 1000;_waiting_arp_internet_datagrams这里存放着等待ARP返回报文的 IP 报文。只有对应 ARP 返回报文到来更新了 ARP 表后网络接口才会知道这些 IP 报文要发送至哪个 MAC 地址。 //! 等待 ARP 报文返回的待处理 IP 报文std::liststd::pairAddress, InternetDatagram _waiting_arp_internet_datagrams{};在实现整个网络接口时必须确保几点 ARP条目 TTL 为30s时间到期后需要将其从 ARP Table 中删除。若发送 IP 报文时发现 ARP Table 中无目标 MAC 地址则立即发送 ARP 请求报文同时将当前 IP 报文暂时缓存直至获取到目标 MAC 地址后再重新发送。不同目标 IP 的 ARP 请求报文之间的发送间隔不能超过 5s。如果 ARP 请求报文在 5 秒内仍然无响应则重新发送。当网络接口接收到一个以太网帧时 必须丢弃目的 MAC 地址不为当前网络接口 MAC 地址除了 ARP 协议需要比较自己的 IP 地址以外不要在其他任何地方进行 IP 比较因为网络接口位于链路层。如果是发给自己的 ARP 请求那么要忽略掉发送来的 ARPMessage::target_ethernet_address因为发送者自己也不知道这个要填写什么该字段无意义。无论接收到的是 ARP 请求包或者 ARP 响应包只要是明确发给自己的那么这里面的 src_ip_addr 和 src_eth_addr 都可用于更新当前的 ARP 表。 具体代码如下: NetworkInterface类核心属性 class NetworkInterface {private://! ARP 条目struct ARP_Entry {EthernetAddress eth_addr;size_t ttl;};//! ARP 表std::mapuint32_t, ARP_Entry _arp_table{};// 默认 ARP 条目过期时间 30sconst size_t _arp_entry_default_ttl 30 * 1000;//! 正在查询的 ARP 报文。如果发送了 ARP 请求后在过期时间内没有返回响应则丢弃等待的 IP 报文std::mapuint32_t, size_t _waiting_arp_response_ip_addr{};// 默认 ARP 请求过期时间 5sconst size_t _arp_response_default_ttl 5 * 1000;//! 等待 ARP 报文返回的待处理 IP 报文std::liststd::pairAddress, InternetDatagram _waiting_arp_internet_datagrams{};//! Ethernet (known as hardware, network-access-layer, or link-layer) address of the interface// 当前虚拟网卡的MAC地址EthernetAddress _ethernet_address;//! IP (known as internet-layer or network-layer) address of the interface// 自己的IP地址Address _ip_address;//! outbound queue of Ethernet frames that the NetworkInterface wants sent// 生产者消费者之间解耦用的队列 -- cs144实现通用套路// 网络适配器只需要把组装好的以太网帧丢入这个队列即可std::queueEthernetFrame _frames_out{};... };如何理解NetworkInterface 一个将IP互联网层或网络层与以太网网络访问层或链路层连接的网络接口该模块是TCP/IP协议栈的最底层连接IP与更底层的网络协议如以太网。但同样的模块也作为路由器的一部分反复使用 路由器通常有许多网络接口其工作是在不同的接口之间路由互联网数据报 网络接口将来自客户端例如TCP/IP协议栈或路由器的数据报转换为以太网帧。为了填写以太网的目标地址它查找每个数据报的下一个IP跳的以太网地址并使用地址解析协议ARP进行请求。在相反的方向网络接口接受以太网帧检查它们是否是针对它的如果是则根据其类型处理有效载荷。如果是IPv4数据报网络接口将其向上传递到协议栈。如果是ARP请求或回复网络接口将处理该帧并根据需要进行学习或回复。 send_datagram 用于发送以太网包,其中涉及ARP广播寻MAC地址的过程 //! \param[in] dgram the IPv4 datagram to be sent //! \param[in] next_hop the IP address of the interface to send it to (typically a router or default gateway, but may also be another host if directly connected to the same network as the destination) //! (Note: the Address type can be converted to a uint32_t (raw 32-bit IP address) with the Address::ipv4_numeric() method.) void NetworkInterface::send_datagram(const InternetDatagram dgram, const Address next_hop) {// convert IP address of next hop to raw 32-bit representation (used in ARP header)const uint32_t next_hop_ip next_hop.ipv4_numeric();// 先查找 APR tableconst auto arp_iter _arp_table.find(next_hop_ip);// 如果 ARP 表中没有目标 MAC 地址if (arp_iter _arp_table.end()) {// 如果已经发送正在等待回应的ARP集合中也不存在,则构建ARP报文并进行发送 -- 防止同一个ARP包在5秒内重复发送if (_waiting_arp_response_ip_addr.find(next_hop_ip) _waiting_arp_response_ip_addr.end()) {// 构建ARP请求ARPMessage arp_request;// 操作码: ARP请求报文arp_request.opcode ARPMessage::OPCODE_REQUEST;// 发送端MAC地址arp_request.sender_ethernet_address _ethernet_address;// 发送端IP地址arp_request.sender_ip_address _ip_address.ipv4_numeric();// 接收端MAC地址待填写 -- 置空arp_request.target_ethernet_address {/* 这里应该置为空*/};// 接收端IP地址 -- 下一跳的IP地址arp_request.target_ip_address next_hop_ip;// 构建以太网帧EthernetFrame eth_frame;// 填充以太网头 -- 目的MAC地址(此处填写ffff,表示广播地址),源MAC地址,payload负载中的协议类型(此处为ARP协议)eth_frame.header() {/* dst */ ETHERNET_BROADCAST,/* src */ _ethernet_address,/* type */ EthernetHeader::TYPE_ARP};// ARP请求序列化后作为以太网帧的payload eth_frame.payload() arp_request.serialize();// 将填充完毕的以太网帧推入_frames_out通道,等待被传输_frames_out.push(eth_frame);// 记录当前发送的ARP请求包, key下一跳IP地址,val该ARP请求的过期时间 -- 防止一个ARP请求在5秒内重复发送_waiting_arp_response_ip_addr[next_hop_ip] _arp_response_default_ttl;}// 将该 IP 包加入等待队列中 -- 等待ARP响应结果来更新目的MAC地址的IP数据报_waiting_arp_internet_datagrams.push_back({next_hop, dgram});} else {// ARP缓存未过期则生成以太网帧并发送EthernetFrame eth_frame;// 目的MAC地址源MAC地址,上一层协议类型为IPV4eth_frame.header() {/* dst */ arp_iter-second.eth_addr,/* src */ _ethernet_address,/* type */ EthernetHeader::TYPE_IPv4}; eth_frame.payload() dgram.serialize();_frames_out.push(eth_frame);} }recv_frame 用于接收以太网数据包 //! \param[in] frame the incoming Ethernet frame optionalInternetDatagram NetworkInterface::recv_frame(const EthernetFrame frame) {// 过滤掉不是发往当前位置的包if (frame.header().dst ! _ethernet_address frame.header().dst ! ETHERNET_BROADCAST)return nullopt;// 如果是 IP 包 if (frame.header().type EthernetHeader::TYPE_IPv4) {InternetDatagram datagram;if (datagram.parse(frame.payload()) ! ParseResult::NoError)return nullopt;//! NOTE: 注意这里不要进行任何 IP 地址的判断, 因为这是链路层协议return datagram;}// 其他情况下是 ARP 包else if (frame.header().type EthernetHeader::TYPE_ARP) {ARPMessage arp_msg;if (arp_msg.parse(frame.payload()) ! ParseResult::NoError)return nullopt;const uint32_t src_ip_addr arp_msg.sender_ip_address;const uint32_t dst_ip_addr arp_msg.target_ip_address;const EthernetAddress src_eth_addr arp_msg.sender_ethernet_address;const EthernetAddress dst_eth_addr arp_msg.target_ethernet_address;// 如果是一个发给自己的 ARP 请求bool is_valid_arp_request arp_msg.opcode ARPMessage::OPCODE_REQUEST dst_ip_addr _ip_address.ipv4_numeric();// 如果是自己发出的ARP请求的回应 bool is_valid_arp_response arp_msg.opcode ARPMessage::OPCODE_REPLY dst_eth_addr _ethernet_address;// 判断是ARP请求和ARP回应if (is_valid_arp_request) {// 如果接受到的ARP请求,那么构造一个ARP回应包ARPMessage arp_reply;arp_reply.opcode ARPMessage::OPCODE_REPLY;arp_reply.sender_ethernet_address _ethernet_address;arp_reply.sender_ip_address _ip_address.ipv4_numeric();arp_reply.target_ethernet_address src_eth_addr;arp_reply.target_ip_address src_ip_addr;EthernetFrame eth_frame;eth_frame.header() {/* dst */ src_eth_addr,/* src */ _ethernet_address,/* type */ EthernetHeader::TYPE_ARP};eth_frame.payload() arp_reply.serialize();_frames_out.push(eth_frame);}// 否则是一个 ARP 响应包//! NOTE: 我们可以同时从 ARP 请求和响应包中获取到新的 ARP 表项if (is_valid_arp_request || is_valid_arp_response) {// 填充ARP表_arp_table[src_ip_addr] {src_eth_addr, _arp_entry_default_ttl};// 将等待ARP响应的IP数据报从原先等待队列里删除for (auto iter _waiting_arp_internet_datagrams.begin(); iter ! _waiting_arp_internet_datagrams.end();/* nop */) {// 找到了等待的IP数据包 if (iter-first.ipv4_numeric() src_ip_addr) {// 再次尝试发送该IP数据包send_datagram(iter-second, iter-first);// 从队列中移除等待中的IP数据包iter _waiting_arp_internet_datagrams.erase(iter);} elseiter;}_waiting_arp_response_ip_addr.erase(src_ip_addr);}}return nullopt; }tick函数定时调用用于删除ARP表中过期条目并且将迟迟未回应的ARP请求进行重发 //! \param[in] ms_since_last_tick the number of milliseconds since the last call to this method // 回忆lab four终章小节中讲到的_tcp_loop事件循环,该函数中会定时调用NetworkInterface的tick函数 // 参数表示: 距离上一次tick函数被调用,过了多长时间 void NetworkInterface::tick(const size_t ms_since_last_tick) {// 将 ARP 表中过期的条目删除for (auto iter _arp_table.begin(); iter ! _arp_table.end(); /* nop */) {if (iter-second.ttl ms_since_last_tick)iter _arp_table.erase(iter);else {iter-second.ttl - ms_since_last_tick;iter;}}// 将 ARP 等待队列中过期的条目删除for (auto iter _waiting_arp_response_ip_addr.begin(); iter ! _waiting_arp_response_ip_addr.end(); /* nop */) {// 如果 ARP 等待队列中的 ARP 请求过期if (iter-second ms_since_last_tick) {// 重新发送 ARP 请求ARPMessage arp_request;arp_request.opcode ARPMessage::OPCODE_REQUEST;arp_request.sender_ethernet_address _ethernet_address;arp_request.sender_ip_address _ip_address.ipv4_numeric();arp_request.target_ethernet_address {/* 这里应该置为空*/};arp_request.target_ip_address iter-first;EthernetFrame eth_frame;eth_frame.header() {/* dst */ ETHERNET_BROADCAST,/* src */ _ethernet_address,/* type */ EthernetHeader::TYPE_ARP};eth_frame.payload() arp_request.serialize();_frames_out.push(eth_frame);iter-second _arp_response_default_ttl;} else {iter-second - ms_since_last_tick;iter;}} }测试 tcp_ip_ethernet.cc lav five主要测试主要集中在tcp_ip_ethernet.cc文件中本节我们来研究一下tcp_ip_ethernet.cc是如何测试的从而更好探究NetworkInterface的工作流程。 首先我们将目光集中在该文件的main入口函数: int main(int argc, char **argv) {try {if (argc 3) {show_usage(argv[0], ERROR: required arguments are missing.);return EXIT_FAILURE;}// choose a random local Ethernet address (and make sure its private, i.e. not owned by a manufacturer)// 为当前主机随机挑选一个MAC地址EthernetAddress local_ethernet_address;for (auto byte : local_ethernet_address) {byte random_device()(); // use a random local Ethernet address}// 设置当前以太网地址为一个私有MAC地址local_ethernet_address.at(0) | 0x02; // 10 in last two binary digits marks a private Ethernet addresslocal_ethernet_address.at(0) 0xfe;// 获取相关配置信息: TCPConfig,FdAdapterConfig,下一跳的IP地址,tap设备名称auto [c_fsm, c_filt, next_hop, tap_dev_name] get_config(argc, argv);// 下面的内容会重点讲解 TCPOverIPv4OverEthernetSpongeSocket tcp_socket(TCPOverIPv4OverEthernetAdapter(TCPOverIPv4OverEthernetAdapter(TapFD(tap_dev_name), local_ethernet_address, c_filt.source, next_hop)));// TCPSpongeSocket的connect和wait_until_closed方法在lab four实验解析中都已给出详细阐述,这里不再多说tcp_socket.connect(c_fsm, c_filt);// 该函数的解析lab four中也进行了讲解bidirectional_stream_copy(tcp_socket);tcp_socket.wait_until_closed();} catch (const exception e) {cerr Exception: e.what() endl;return EXIT_FAILURE;}return EXIT_SUCCESS; }关于cs144中提供的适配器和Socket体系,lab four实验解析中已经详细阐述了这里我们重点关注TCPOverIPv4OverEthernetAdapter和TCPOverIPv4OverEthernetSpongeSocket TCPOverIPv4OverEthernetAdapter TCPOverIPv4OverEthernetAdapter适配器负责从TAP设备读写IPV4数据报: // A FD adapter for IPv4 datagrams read from and written to a TAP device class TCPOverIPv4OverEthernetAdapter : public TCPOverIPv4Adapter {private:TapFD _tap; // Raw Ethernet connection -- 可以把Tap看做网卡驱动加网卡NetworkInterface _interface; // NIC abstractionAddress _next_hop; // IP address of the next hop... };read: 从tap设备读取以太网帧,并交给链路层的NetworkInterface处理,得到IPV4数据报,然后从IP数据报提取tcp报文返回 optionalTCPSegment TCPOverIPv4OverEthernetAdapter::read() {// Read Ethernet frame from the raw deviceEthernetFrame frame;// 从tap设备读取数据,并解析为以太网帧if (frame.parse(_tap.read()) ! ParseResult::NoError) {return {};}// Give the frame to the NetworkInterface. Get back an Internet datagram if frame was carrying one.// 从以太网帧中提取IPV4数据报 -- NetworkInterface的recv_frame方法,本lab实现的optionalInternetDatagram ip_dgram _interface.recv_frame(frame);// The incoming frame may have caused the NetworkInterface to send a frame.// 将NetworkInterface输出队列中待发送的数据包取出并写入tap设备,即发送出去send_pending();// Try to interpret IPv4 datagram as TCP// 从ip数据报中提取tcp segment返回if (ip_dgram) {return unwrap_tcp_in_ip(ip_dgram.value());}return {}; }write 将tcp报文段包装为IP数据报然后交给NetworkInterface进行处理处理完毕后得到对应的以太网帧然后放入frames_out输出队列 //! \param[in] seg the TCPSegment to send void TCPOverIPv4OverEthernetAdapter::write(TCPSegment seg) {// 将待写入的tcp数据报添加IP头,成为IP数据报,然后交给数据链路层处理 -- NetworkInterface将处理好的以太网帧放入frames_out中_interface.send_datagram(wrap_tcp_in_ip(seg), _next_hop);// 将NetworkInterface输出队列中待发送的数据包取出并写入tap设备,即发送出去send_pending(); }send_pending: 将frames_out输出队列中待发送的以太网帧取出交给tap设备发送出去 // 将NetworkInterface输出队列中待发送的数据包取出并写入tap设备,即发送出去 void TCPOverIPv4OverEthernetAdapter::send_pending() {while (not _interface.frames_out().empty()) {_tap.write(_interface.frames_out().front().serialize());_interface.frames_out().pop();} }每次读取以太网帧的时候顺便将输出队列待发送的数据报一把梭哈这个操作很类似redis过期key的lazy回收。 tick: 定时调用NetworkInterface的tick方法,同时帮忙清空输出队列 //! \param[in] ms_since_last_tick the number of milliseconds since the last call to this method void TCPOverIPv4OverEthernetAdapter::tick(const size_t ms_since_last_tick) {_interface.tick(ms_since_last_tick);send_pending(); }TCPOverIPv4OverEthernetSpongeSocket TCPOverIPv4OverEthernetSpongeSocket本身是TCPSpongeSocket模板类的一个实例化类型的别名: using TCPOverIPv4OverEthernetSpongeSocket TCPSpongeSocketTCPOverIPv4OverEthernetAdapter;关于TCPSpongeSocket类的讲解在lab four实验解析中已经做出过详细阐述了这里不再重复。 通信过程 首先tcp_ip_ethernet.cc的main函数中调用connect函数初始化事件循环并开启事件循环该函数源码如下: //! \param[in] c_tcp is the TCPConfig for the TCPConnection //! \param[in] c_ad is the FdAdapterConfig for the FdAdapter template typename AdaptT void TCPSpongeSocketAdaptT::connect(const TCPConfig c_tcp, const FdAdapterConfig c_ad) {if (_tcp) {throw runtime_error(connect() with TCPConnection already initialized);}// 初始化TCP连接和事件循环_initialize_TCP(c_tcp);_datagram_adapter.config_mut() c_ad;cerr DEBUG: Connecting to c_ad.destination.to_string() ...\n;// 开始三次握手,首先由Client发出一个SYN包_tcp-connect();const TCPState expected_state TCPState::State::SYN_SENT;if (_tcp-state() ! expected_state) {throw runtime_error(After TCPConnection::connect(), state was _tcp-state().name() but expected expected_state.name());}// 使用事件循环,等待三次连接建立完毕_tcp_loop([] { return _tcp-state() TCPState::State::SYN_SENT; });cerr Successfully connected to c_ad.destination.to_string() .\n;// 单独开启一个线程用于后续数据传输 _tcp_thread thread(TCPSpongeSocket::_tcp_main, this); }主线程调用bidirectional_stream_copy初始化并启动一个事件循环实现键盘输入的数据会写入socket,socket有可读的数据会输出到屏幕上的功能。 本节涉及函数均在lab four中给出了详细解释本节不再多讲。 最终主线程事件循环和子线程事件循环共同协作完成数据收发功能: 键盘输入 屏幕显示 但是这里要提到一点 , 就是开启事件循环的_tcp_loop函数会定期调用TCPOverIPv4OverEthernetAdapter的tick方法而TCPOverIPv4OverEthernetAdapter的tick方法调用的又是NetworkInterface的tick方法: //! \param[in] condition is a function returning true if loop should continue template typename AdaptT void TCPSpongeSocketAdaptT::_tcp_loop(const functionbool() condition) {auto base_time timestamp_ms();// 什么时候停止事件循环取决于condition函数返回值while (condition()) {// 等待获取下一个待发生的rule,超时则返回 -- 超时时间为10毫秒auto ret _eventloop.wait_next_event(TCP_TICK_MS);// 没有事件发生,说明TCP断开了连接if (ret EventLoop::Result::Exit or _abort) {break;}// 如果tcp连接仍然活跃if (_tcp.value().active()) {// 每隔10毫秒,调用一次TCPConnection的tick方法const auto next_time timestamp_ms();// 传入参数: 距离上次调用该方法过了多久_tcp.value().tick(next_time - base_time);// 只有TCPOverIPv4OverEthernetAdapter的tick函数才有意义// 其他adapter均为空实现_datagram_adapter.tick(next_time - base_time);base_time next_time;}} }
http://www.hkea.cn/news/14311031/

相关文章:

  • 兼职 网站 小程序 建设做站群网站会被k吗
  • 网站做自签发证书设计相关的网站有哪些内容
  • 电子商务网站建设评估的工具广州外贸网站建设 open
  • 外贸网站风格曲阳县做网站
  • 了解网站开发的背景大型网站建设济南兴田德润团队怎么样
  • wordpress商品资源怎么做网站优化推广
  • 北京市网站公司网站电商小程序平台
  • 站群网站建设推广彩票做的最好是个网站好
  • 洛阳网站推广优化品牌建设 企业要
  • 学工网站建设wordpress 煎蛋
  • 开网站建设公司赚钱吗wordpress如何应用插件下载
  • 网站开发需要准备什么自己做网站需要买什么
  • 怎么做网站内部链接库尔勒网站
  • 佛山网站建站建设保定网站设计制作
  • 如皋网站定制wordpress 柚子皮下载
  • 模板网站建设代理商张家港快速网站建设
  • 马鞍山集团网站建设wordpress制作单页
  • 营口网站建设公司上海最好的网站建设公司
  • 网站被黑怎么办tk免费域名注册
  • 可以帮忙做网站做公司专门做库存的网站
  • 企业网站seo名称想在网站里添加超链接怎么做
  • 杭州网站的制作创建手机网页
  • 网站开发维护入哪个科目丹东制作网站公司
  • 黄岛区建设局网站石家庄网站推广报价
  • 加强门户网站建设提升好的html5网站模板
  • 网站开发建设协议眉山做网站
  • 人力资源招聘网站建设方案柳市哪里有做网站推广
  • 自己创建的网站怎么做流量代理网店童装
  • 惠州网站建设是什么意思wordpress搭建下载站
  • 南通哪里学网站建设彩票开发网站建设应该要注意哪些问题