苏嵌实训——day18

news2024/12/29 8:19:25

文章目录

  • 一 wirkeshark 抓包工具
    • 1.1 软件介绍
    • 1.2 软件安装
    • 1.3 wireshark工具的使用
    • 1.4 TCP三次握手和四次挥手
  • 二 TCP循环服务器
    • 2.1 IO多路复用
    • 2.2 使用select实现IO多路复用
    • 2.3 epoll

一 wirkeshark 抓包工具

1.1 软件介绍

wireshark用于抓取经过我当前主机网卡的所有的数据包并且会自动分析数据包
网络管理员使用wireshark来检测网络问题
网络安全工程师使用wireshark来检查资讯安全相关的问题
开发者使用wireshark来为新的通讯协定除错。
普通使用者使用wireshark来学习网络协议的相关知识。

1.2 软件安装

安装此工具,一路下一步即可,有选择插件usbpcap需要打勾安装一下。

1.3 wireshark工具的使用

第一步:使用管理员权限打开软件
在这里插入图片描述

第二步 选择合适的网卡
在这里插入图片描述

或者在菜单栏中选择“捕获”,点击“选项”,选择适当的网卡
在这里插入图片描述

第三步 查看数据包信息
在这里插入图片描述

增加过滤条件
在这里插入图片描述
在这里插入图片描述

1.4 TCP三次握手和四次挥手

Tcp三次握手主要指的是TCP的连接过程
三次握手主要是在客户端的connect和服务器的listen,accpet函数之间完成的
TCP的四次挥手主要指的是TCP的断开连接的过程
四次挥手主要是在客户端服务器退出或者关闭文件描述符的时候完成的
在这里插入图片描述在这里插入图片描述

二 TCP循环服务器

2.1 IO多路复用

当一个代码中有多个阻塞函数的时候,因为代码默认都有先后执行顺序,所以无法做到每一个阻塞函数独立执行,相互没有影响,如何解决这个问题?
如果按照默认阻塞形式,无法解决
如果设置为非阻塞,每一个函数都轮询查看缓冲区是否有数据,可以解决这个问题,但是轮询比较占cpu资源,所以不推荐
如果使用多线程或者多进程,需要考虑资源释放的问题,也不推荐
相对比较号的方式是使用IO多路复用
IO多路复用的思想是:
先构造一张有关描述符的表,保存要操作的描述符
然后调用一个函数,阻塞等待文件描述符准备就绪,
当有文件描述符准备就绪,则函数立即返回,执行相应的IO操作。
在这里插入图片描述

2.2 使用select实现IO多路复用

头文件:#include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

原型:int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);
功能:允许一个程序操作多个文件描述符,阻塞等待文件描述符,准备就绪,如果有文件描述符准备就绪,函数立即返回,执行相应的IO操作。
参数:
    nfds:最大的文件描述符+1
    readfds:保存读操作文件描述符的集合
    writefds:保存写操作文件描述符的集合
    exceptfds:操作其它或者异常的文件描述符的集合
    timeout:超时
            null:阻塞
返回值:
    成功:准备就绪的文件描述符的个数
    失败:返回-1
//将文件描述符fd从集合set中移除
void FD_CLR(int fd, fd_set *set);
//判断文件描述符是否在集合set中

int  FD_ISSET(int fd, fd_set *set);
//将文件描述符fd添加到集合set中
void FD_SET(int fd, fd_set *set);
//清空集合set

void FD_ZERO(fd_set *set);
返回值:
    存在:1
    不存在:0
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char const *argv[])
{
    //创建套接字
    int sockfd = socket(AF_INET,SOCK_STREAM,0);  //IPV4    流式套接字   具体协议类型
    if(-1 == sockfd)
    {
        perror("socket");
        return -1;
    }
    int opt = 1;
    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));  //设置地址可以被重复绑定

    struct sockaddr_in server_addr;
    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("192.168.98.145");   //127.0.0.1回环ip,表示本机,测试时可以使用
    server_addr.sin_port = 8888;

    //绑定信息
    int ret = bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
    if(ret == -1)
    {
        perror("bind");
        return -1;
    }
    //设置监听队列
    ret = listen(sockfd,10);
    if(ret == -1)
    {
        perror("listen");
        return -1;
    }

    fd_set readfd,tmpfd;  //定义集合
    FD_ZERO(&readfd);   //清空集合
    FD_SET(sockfd,&readfd); //添加到集合

    int maxfd = sockfd;
    int fd[1024] = {0},i =0;
    struct sockaddr_in client_addr;   //用于保存客户端的信息
    int length = sizeof(client_addr);
    char buf[32] = {0};
    while(1)   //循环服务器
    {
        tmpfd = readfd;
        ret = select(maxfd + 1,&tmpfd,NULL,NULL,NULL); //监听集合是否可读,最后一个NULL表示阻塞
        if(ret == -1)
        {
            perror("select");
            return -1;
        }
        //如果有文件描述符可读
        if(FD_ISSET(sockfd,&tmpfd))    //判断sockfd是否还留在集合里面,判断是否有客户端发起连接
        {
            for(i = 0; i < 1024;i++)   //选择合适的fd[i]
            {
                if(fd[i] == 0)
                {
                    break;
                }
            }
            fd[i] = accept(sockfd,(struct sockaddr *)&client_addr,&length);
            if(-1 == fd[i])
            {
                perror("accept");
                return -1;
            }
            printf("接收到来自%s的客户端的连接fd = %d\n",inet_ntoa(client_addr.sin_addr),fd[i]);
            FD_SET(fd[i],&readfd);   //将新的文件描述符加入到集合中
            if(maxfd < fd[i])
            {
                maxfd = fd[i];
            }
        }
        else    //有客户端发消息
        {
            for(i = 0 ; i < 1024;i++)
            {
                if(FD_ISSET(fd[i],&tmpfd))   //判断哪个fd可读
                {
                    ret = recv(fd[i],buf,sizeof(buf),0);
                    if(ret == -1)
                    {
                        perror("recv");
                    }
                    else if(ret == 0)
                    {
                        close(fd[i]);  //关闭TCP连接
                        FD_CLR(fd[i],&readfd);
                        printf("客户端%d下线!\n",fd[i]);
                        fd[i] = 0;
                    }
                    else
                    {
                        printf("收到%d客户端的消息%s\n",fd[i],buf);
                    }
                    memset(buf,0,sizeof(buf));
                    break;
                }
            }
        }
    }
    return 0; 
}
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include<arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    //创建套接字
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd == -1)
    {
        perror("socket");
        return -1;
    }
    //向服务器发起连接
    struct sockaddr_in server_addr;   //保存服务器的信息
    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = 8888;
    server_addr.sin_addr.s_addr = inet_addr("192.168.98.145");
    int ret = connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
    if(-1 == ret)
    {
        perror("connect");
        return -1;
    }
    char buf[32] = {0};
    while(1)
    {
        scanf("%s",buf);
        ret = send(sockfd,buf,strlen(buf),0);
        if(-1 == ret)
        {
            perror("send");
            return -1;
        }
        if(strcmp(buf,"bye") == 0)
        {
            break;
        }
        memset(buf,0,sizeof(buf));
    }
    close(sockfd);
    return 0;
}

2.3 epoll

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#define MAXSIZE 256
int main(int argc, char const *argv[])
{
    //创建套接字
    int sockfd = socket(AF_INET,SOCK_STREAM,0);  //IPV4    流式套接字   具体协议类型
    if(-1 == sockfd)
    {
        perror("socket");
        return -1;
    }
    int opt = 1;
    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));  //设置地址可以被重复绑定


    struct sockaddr_in server_addr;
    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("192.168.98.145");   //127.0.0.1回环ip,表示本机,测试时可以使用
    server_addr.sin_port = 8888;


    //绑定信息
    int ret = bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
    if(ret == -1)
    {
        perror("bind");
        return -1;
    }
    //设置监听队列
    ret = listen(sockfd,10);
    if(ret == -1)
    {
        perror("listen");
        return -1;
    }  
    //创建epoll对象
    int epfd = epoll_create(MAXSIZE);
    if(-1 == epfd)
    {
        perror("epoll_create");
        return -1;
    }
    struct epoll_event ev,events[MAXSIZE] = {0};
    ev.data.fd = sockfd;   //设置监听socket可读
    ev.events = EPOLLIN;
    //将所有需要监听的socket添加到epfd中
    ret = epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);
    if(-1 == ret)
    {
        perror("epoll_ctl");
        return -1;
    }
    int i;
    struct sockaddr_in client_addr;
    int length = sizeof(client_addr);
    char buf[32] = {0};
    while(1)
    {
        int num = epoll_wait(epfd,events,MAXSIZE,-1);   // -1表示阻塞
        if(-1 == num)
        {
            perror("epoll_wait");
            return -1;
        }
        for(i = 0; i < num;i++)
        {
            if(events[i].data.fd == sockfd)   //有客户端发起连接
            {
                int fd = accept(sockfd,(struct sockaddr *)&client_addr,&length);
                if(-1 == fd)
                {
                    perror("accept");
                    return -1;
                }
                printf("接收来自%s的连接fd = %d\n",inet_ntoa(client_addr.sin_addr),fd);
                //为新的文件描述符注册事件
                ev.data.fd = fd;
                ev.events = EPOLLIN;
                ret = epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev);
                if(-1 == ret)
                {
                    perror("epoll_ctl");
                    return -1;
                }               
            }
            else    //客户端发消息
            {
                if(events[i].events & EPOLLIN)   //如果事件是可读的
                {
                    ret = recv(events[i].data.fd,buf,sizeof(buf),0);
                    if(ret == -1)
                    {
                        perror("recv");
                    }
                    else if(ret == 0)  //客户端退出  ,注销事件
                    {
                        printf("客户端%d下线!\n",events[i].data.fd);
                        ev.data.fd = events[i].data.fd;
                        ev.events = EPOLLIN;
                        epoll_ctl(epfd,EPOLL_CTL_DEL,events[i].data.fd,&ev);
                        close(events[i].data.fd);
                    }
                    else
                    {
                        printf("收到 %d客户端的消息 %s\n",events[i].data.fd,buf);
                    }
                }
            }
        }
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/189926.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ffmpeg解封、解码实战

1 概述 2 解封装相关函数接口 avformat_alloc_context();负责申请一个AVFormatContext结构的内存,并进行简单初始化 avformat_free_context();释放该结构里的所有东西以及该结构本身 avformat_close_input();关闭解复用器。 avformat_open_input();打开输入视频文件 avformat_…

在elasticsearch中简单的使用script_fields

文章目录1、背景2、准备数据2.1 mapping2.2 插入数据3、案例3.1 格式化性别 1-男 2-女 -1-未知 如果不存在sex字段&#xff0c;则显示-- 其余的显示 **3.1.1 dsl3.1.2 java代码3.1.3 运行结果3.2 判断用户是否有某个爱好3.2.1 dsl3.2.2 java代码3.2.3 运行结果3.3 统计湖北的用…

Oracle 程序被编译后自动增加了AUTHID CURRENT_USER授权

目录 背景 原因&#xff1a; 解决方法 背景 今天遇到一个大坑&#xff0c;新建的一个数据库用户调用apps下的程序包&#xff0c;程序反馈未授权无法使用。 但是DBA确认已经给了授权。 查询授权表也是有正确授权的&#xff0c;但就是显示无效授权。 后来debug进去&#x…

外汇k线图经典图解:穿头破脚

从事外汇、黄金交易怎么能不懂K线图&#xff0c;学看K线图怎么能不把一些经典图解铭记心中呢&#xff1f;它们就好比字典和工具书&#xff0c;当投资者在解读行情时遇到任何困惑&#xff0c;都能从这些经典中得到指引&#xff0c;从而指明自己的投资方向。今天&#xff0c;小编…

java ssm校园二手书交易平台idea

该网站从实际运用的角度出发&#xff0c;运用了计算机网站设计、数据库等相关知识&#xff0c;网络和Mysql数据库设计来实现的&#xff0c;网站主要包括学生注册、学生登录、浏览图书、搜索图书、查看图书并进行购买&#xff0c;对购买的图书进行确认收货、退款退货、查看个人信…

Elasticsearch连续剧之实战篇Java操作es

作者&#xff1a;狮子也疯狂 专栏&#xff1a;《es》 坚持做好每一步&#xff0c;幸运之神自然会驾凌在你的身上 目录一、&#x1f407;前言二、&#x1f407;原生JAVA操作ES_搭建项目Ⅰ、创建项目Ⅱ、索引操作2.1 创建空索引2.2 给索引添加结构2.3 删除索引Ⅲ、文档操作3.1 新…

vCloud删除OVDC网络时提示被vApp网络使用无法删除

环境 VMware Cloud Director 版本:10.3.2.19375051 现象 在vCloud租户视图删除OVDC网络,提示被vApp网络使用,无法删除。此时通过查看vApp发现并没有残留vApp网络。 解决办法 1、登录vCloud数据库: 登录方法可以参考:VMware Cloud Director数据库操作 2、查逻辑网络: …

CAN接口电路设计

CAN总线的全称是控制器局域网络&#xff0c;主要应用在汽车电子和工业控制领域。和485总线一样&#xff0c;CAN总线也是一种半双工的通信。一条CAN总线最多能接110个节点它最高速率能到1Mbps&#xff0c;最远传输距离能到10KMCAN总线有两个信号&#xff0c;一个是CANH&#xff…

如何在 Linux 命令行中优雅的格式化输出 xml,记住这三种方法!

xml&#xff08;可扩展标记语言&#xff09;也是一种人类可读的标记语言&#xff0c;但是如同 json 文件一样&#xff0c;没有缩进格式&#xff08;或者压缩&#xff09;的 xml 文件&#xff0c;读起来那是挺头疼的。 首先来看一下我们这篇文章要达到的目的&#xff0c;如下图…

代码随想录训练营第十七天|110.平衡二叉树 ● 257. 二叉树的所有路径 ● 404.左叶子之和

110.平衡二叉树 看完题后的思路 int[] f(root)if rootnull return [true,0]left[]f(root.left) if(!left[0]){return [false,-1]} right[]f(root.right) if(!right[0]){return [false,-1]} return[true,math.max(left[1],right[1])1] 思路 上面的过程弄复杂了&#xff0c;其…

Elasticsearch 入门到精通-Elasticsearch核心倒排索引数据结构

Elasticsearch 简介Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。Elasticsearch 建立在全文搜索引擎 Apache Lucene™ 基础上&#xff0c;通过 Lucene 的倒排索引技术实现比关系型数据库更快的过滤&#xff0c;从而很方便的使大量数据具有搜索、分析和探索…

vue插槽之插槽的用法及作用域插槽详解

目录前言一&#xff0c;插槽的基本使用1.1 引出插槽1.2 插槽的基本使用1.3 默认插槽1.4 插槽样式二&#xff0c;具名插槽2.1 引出具名插槽2.2 具名插槽的使用三&#xff0c;template标签3.1 引出template标签3.2 template标签的使用四&#xff0c;作用域插槽4.1 引出作用域插槽…

C语言小题,有3个学生的信息,放在结构体数组中,要求输出全部学生的信息。(指向结构体数组的指针)

前言&#xff1a; 此篇是针对 指向结构体数组的指针 方面的练习。 解题思路&#xff1a; 用指向结构体变量的指针来处理&#xff1a; &#xff08;1&#xff09;声明结构体类型 struct Student &#xff0c;并定义结构体数组&#xff0c;同时使之初始化&#xff1b; &#xff…

【Rust】9. 常见集合

9.1 Vector 9.1.1 创建 vector vector 只能储存相同类型的值&#xff01;创建空的 vector&#xff1a;Vec::new()创建有值的 vector&#xff1a;vec! 宏 9.1.2 向 vector 中添加元素 9.1.3 读取 vector 的元素 索引语法&#xff1a;当引用一个不存在的元素时 Rust 会造成 pa…

设计模式-软件设计原则

目录 3.软件设计原则 3.1 开闭原则 3.2 里氏代换原则 3.3 依赖倒转原则 3.4 接口隔离原则 3.5 迪米特法则 3.6 合成复用原则 3.软件设计原则 在软件开发中&#xff0c;为了提高软件系统的可维护性和可复用性&#xff0c;增加软件的可扩展性和灵活性&#xff0c;程序员要…

【QT5 定时器练习-笔记-样例讲解-实现方式>>>(1)定时器事件方式和(2)定时器绑定函数】

QT5 -定时器简单应用-样例讲解-实现方式1-定时器事件方式1、前言2、实验环境3、定时器实现方式说明-以及效果3、操作步骤-&#xff08;1&#xff09;定时器事件方式&#xff08;1&#xff09;建立工程&#xff08;2&#xff09;拉控件布局&#xff08;3&#xff09;代码部分编写…

《深入浅出计算机组成原理》学习笔记 Day16

冒险和预测&#xff08;一&#xff09;1. 超长流水线的缺点2. 冒险和分支预测参考1. 超长流水线的缺点 增加流水线的深度&#xff0c;在同主频下&#xff0c;其实就是降低了 CPU 的性能。 一个 Pipeline Stage&#xff0c;就需要一个时钟周期。如果我们把任务分成 31 个阶段&…

2014年408专业算法题

文章目录0 结果1 题目2 思路附录0 结果 1 题目 2 思路 二叉树的带权路径长度&#xff08;WPL&#xff09;的计算方法有两种&#xff1a; 1&#xff0c;定义&#xff1a;WPL所有叶结点的权值Wi∗该结点深度Di求和WPL所有叶结点的权值W_i*该结点深度D_i求和WPL所有叶结点的权值…

如何管理IC研发过程产生的bug

一款芯片的研发过程中总是伴随着bug、bug和bug&#xff0c;研发线上各端的IC工程师也是全程在debug、debug和debug&#xff0c;直到最终的GDSII文件交给Founry工厂加工&#xff0c;全程都是为了保证芯片最终能够安全保质的tape-out成功。由此可见&#xff0c;bug的跟踪管理是至…

【数据结构】题解:二叉树的非递归遍历

【数据结构】题解&#xff1a;二叉树的非递归实现 文章目录【数据结构】题解&#xff1a;二叉树的非递归实现一、问题描述二、递归实现三、非递归实现3.1 前序遍历3.2 中序遍历3.3 后序遍历一、问题描述 二叉树的前序遍历&#xff0c;非递归迭代实现 &#xff0c;二叉树的前序遍…