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

(9)下:学习与验证 linux 里的 epoll 对象里的 EPOLLIN、 EPOLLHUP 与 EPOLLRDHUP 的不同。小例子的实验

(4)本实验代码的蓝本,是伊圣雨老师里的课本里的代码,略加改动而来的。
++以下是 服务器端的代码:

在这里插入图片描述

++ 每当收到客户端的报文时,就测试一下对应的 epoll 事件里的事件标志,不读取报文内容,所以设置为 ET 边缘触发模式。
++ 对应的代码版本 :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h> //增加这俩头文件
#include <errno.h>#define EPOLL_SIZE  50int main(int argc,char * argv[])
{   //验证 EPOLLHUP 等标志的服务器端, argc = 2int serv_sock, clnt_sock, str_len, i, epfd, event_cnt;struct sockaddr_in serv_adr, clnt_adr;socklen_t adr_sz;  struct epoll_event event, * ep_events;if(argc != 2) { printf("参数不是2个\n");exit(1); }serv_sock = socket(PF_INET,SOCK_STREAM,0);printf("创建了监听套接字,描述符为: %d\n",serv_sock);memset(&serv_adr,0,sizeof(serv_adr));serv_adr.sin_family = AF_INET; // 协议serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址serv_adr.sin_port = htons(atoi(argv[1])); //端口号bind( serv_sock,(struct sockaddr *)&serv_adr, sizeof(serv_adr) ) ;listen(serv_sock,5);epfd = epoll_create(EPOLL_SIZE); // EPOLL_SIZE = 50event.events  = EPOLLIN; // 监听套接字仍为水平触发模式event.data.fd = serv_sock;epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);ep_events = malloc(sizeof(struct epoll_event) * EPOLL_SIZE);while (1) // 此循环在正常情况下是不会退出的。{   event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);       if(-1 == event_cnt) {  break; } // 出错则结束循环,进程退出   puts("从 epoll_wait() 返回了");//统计epoll_wait()的返回次数for(i = 0 ; i < event_cnt ; i++) //依次处理所有发生了事件的套接字{   if(ep_events[i].data.fd == serv_sock)//监听套接字{   adr_sz = sizeof(clnt_adr);clnt_sock = accept( serv_sock,(struct sockaddr *)&clnt_adr,&adr_sz );event.events = EPOLLIN | EPOLLHUP |EPOLLRDHUP | EPOLLET ;// 通信套接字用边缘触发是因为不准备读取报文event.data.fd = clnt_sock; epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event); printf("创建了通信套接字 id: %d\n", clnt_sock);} else { // 依次测试通讯套接字上有事件时具有的 epoll标志。uint32_t revents = ep_events[i].events; int fd = ep_events[i].data.fd;if( revents & EPOLLIN    ) printf("通信套接字 %d 上有 EPOLLIN    事件\n", fd);if( revents & EPOLLHUP   ) printf("通信套接字 %d 上有 EPOLLHUP   事件\n", fd);if( revents & EPOLLRDHUP ) printf("通信套接字 %d 上有 EPOLLRDHUP 事件\n", fd);}} // for(...)  } // while(...)return 0;  
}

(5) 接着给出客户端的版本,这是一个 linux 版本的客户端,很简单的小程序

在这里插入图片描述

++ 记录其源代码版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>int main(int argc,char * argv[])
{   // 回声客户端,三个参数,argc = 3int  sock, str_len;  struct sockaddr_in  serv_adr;if(argc != 3) { printf("参数不是3个\n");exit(1); }sock = socket(PF_INET,SOCK_STREAM,0);memset(&serv_adr,0,sizeof(serv_adr));serv_adr.sin_family = AF_INET;// serv_adr.sin_addr.s_addr = inet_addr(argv[1]);// inet_addr() 的语义不明,不好// 处理文本地址,只需使用 inet_pton() 与 inet_ntop() 即可。// int inet_pton(int af, const char *src, void *dst);inet_pton(AF_INET, argv[1], &serv_adr.sin_addr.s_addr);serv_adr.sin_port = htons(atoi(argv[2]));if(connect(sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) != -1)puts("客户端套接字连接至服务器成功\n");sleep(60); // 延迟 60s 以观察实验结果close(sock); // 此行可注释,以验证 四次握手与 RST 报文的出现时机exit(0);
}

(6)后来实验中发现,客户端采用 linux 版本,会导致 wireshark 无法抓包,只好再编写 windows 版本的客户端,源代码如下:

在这里插入图片描述

++ 代码版:

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>#pragma warning(disable : 4996) // 禁用关于 inet_addr 的过时警告int main() 
{WSADATA m_wsadata; // 在 windows平台使用 socket前,须做一下初始化,WSAStartup(0x0202, &m_wsadata); // 最后用 WSACleanup() 释放库。SOCKET sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);SOCKADDR_IN       server_in;memset(&server_in, 0, sizeof(SOCKADDR_IN));  //连接服务器server_in.sin_family = AF_INET;server_in.sin_port = htons(9000); // 连接至 80 端口server_in.sin_addr.s_addr = inet_addr("192.168.1.126");connect(sClient, (struct sockaddr*)&server_in, sizeof(SOCKADDR_IN));for (int i = 0; i < 1000000000; i++); // 延时一下closesocket(sClient); // 关闭套接字的函数WSACleanup();         // 用这个函数关闭库return 0; 
}

++ 使用 windows 的套接字,还要设置一下 vs2019 ,要不然上面的代码会找不到外部函数

在这里插入图片描述

++ 以及:

在这里插入图片描述

(7) 以下给出实验结果,配合 wireshark 抓包

在这里插入图片描述

(8)

谢谢

http://www.lryc.cn/news/530597.html

相关文章:

  • DeepSeek-R1模型1.5b、7b、8b、14b、32b、70b和671b有啥区别?
  • 一、html笔记
  • AI大模型开发原理篇-2:语言模型雏形之词袋模型
  • 基于微信小程序的实习记录系统设计与实现(LW+源码+讲解)
  • 【LLM】DeepSeek-R1-Distill-Qwen-7B部署和open webui
  • 【Elasticsearch】 Intervals Query
  • DeepSeek技术深度解析:从不同技术角度的全面探讨
  • Docker 部署 Starrocks 教程
  • 【LLM-agent】(task6)构建教程编写智能体
  • 29.Word:公司本财年的年度报告【13】
  • 14 2D矩形模块( rect.rs)
  • 【Unity3D】实现2D角色/怪物死亡消散粒子效果
  • Linux - 进程间通信(3)
  • 3、C#基于.net framework的应用开发实战编程 - 实现(三、三) - 编程手把手系列文章...
  • C++编程语言:抽象机制:泛型编程(Bjarne Stroustrup)
  • Python面试宝典13 | Python 变量作用域,从入门到精通
  • 基于最近邻数据进行分类
  • DeepSeek V3 vs R1:大模型技术路径的“瑞士军刀“与“手术刀“进化
  • 一、TensorFlow的建模流程
  • 指导初学者使用Anaconda运行GitHub上One - DM项目的步骤
  • 7层还是4层?网络模型又为什么要分层?
  • C++:抽象类习题
  • C++ 泛型编程指南02 (模板参数的类型推导)
  • 音视频入门基础:RTP专题(5)——FFmpeg源码中,解析SDP的实现
  • 计算机网络 应用层 笔记 (电子邮件系统,SMTP,POP3,MIME,IMAP,万维网,HTTP,html)
  • 【视频+图文详解】HTML基础3-html常用标签
  • FreeRTOS学习 --- 消息队列
  • PHP If...Else 语句详解
  • pytorch使用SVM实现文本分类
  • 安卓(android)读取手机通讯录【Android移动开发基础案例教程(第2版)黑马程序员】