文章目录

  • 一 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:最大的文件描述符+1readfds:保存读操作文件描述符的集合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);
//清空集合setvoid 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;
}

苏嵌实训——day18相关推荐

  1. 【苏嵌实训-嵌入式 linux C 第 1天】

    | 项目名称 [苏嵌实训-嵌入式 linux C 第 1天] 今日进度以及任务 了解未来就业形势.学习Linux系统开发环境,熟悉编译环境和命令. 任务完成情况 通过在微信公众号及百度搜索完成 本日开 ...

  2. 苏嵌实训-嵌入式Linux C 第一天

    项目名称 苏嵌实训-嵌入式Linux C 第一天 今日进度以及任务 嵌入式开发概述及嵌入式LinuxC项目演示 今日开发中出现的问题汇总 1.嵌入式底层开发为什么选择C语言? 2.什么是实时性?硬实时 ...

  3. 苏嵌实训——day2

    文章目录 一.C语言简单讲解 1.1 代码注释 1.2 中英文切换 1.3 代码讲解 gcc编译出现问题的解决方式 二. 计算机的数据表示 数值型数据 非数值型数据 三.词法符号 3.1 关键词 3. ...

  4. 苏嵌实训——day7

    文章目录 一 Makefile简介 1.1什么是Makefile? 1.2什么是make? 1.3为什么使用? 1.4.优越性 二.makefile 2.1 makfile编译规则 2.2 Makef ...

  5. 苏嵌实训——day19

    文章目录 一.数据库 1.1 在ubuntu中安装数据库 1.2 数据库的操作 1.2.1 数据库命令的分类 1.2.2 常用的系统命令 1.2.3 数据中的常用的语句 1.3 sqlite数据库中常 ...

  6. 苏嵌实训——day9

    文章目录 一 单链表 1.1 概念 1.2 单链表的操作 1.2.1 定义结点结构体 1.2.2 创建一个空的单链表 1.2.3 头插法插入数据 1.2.4 遍历单链表 1.2.5 尾插法插入数据 1 ...

  7. 苏嵌实训——day11

    文章目录 一.队列 1.1 队列的概念 1.2 链式队列 1.2.1 linkqueue.h 1.2.2 linkqueue.c 1.3 顺序队列(循环队列) 1.3.1 sequeue.h 1.3. ...

  8. 苏嵌实训——day1

    文章目录 一.概述 二.Linux 三.linux的系统的层次 四.linux目录结构 五.命令行提示符的介绍 六.linux的基本命令 6.1 ls命令 6.2 chmod命令 6.3 cd 命令 ...

  9. 苏嵌实训——day4

    文章目录 一. 数组 1.1 数组的概念 1.2 一维数组 1.2.1 一维数组的定义 1.2.2 一维数组的性质 1.3 一维数组的初始化和遍历 1.4 冒泡排序 二.二维数组 2.1 二维数组的定 ...

最新文章

  1. 如何基于Kubernetes构建完整的DevOps流水线
  2. OpenCV2:开头篇 介绍
  3. c语言常用的异常处理,C语言中的异常处理
  4. html表格数据点击事件,如何在iview的table单元格里实现点击事件?
  5. 《乌合之众》读书笔记(part1)--对群体而言,最不公正的也许却是最好的
  6. 【转载】315M无线模块数据传输——深入研究
  7. eNet 软件发布要求多多
  8. 系统对接方案_一个呼叫中心系统组建的案例
  9. IBGP的自己下一跳,指定源命令。
  10. 遇到一点难题,请大拿帮忙看一下 万分感谢
  11. 黑客是用idle还是python_python学习一定用pycharm吗?再看看还有什么其他IDE可以选择...
  12. HTML用画布画哆啦A梦,前端小项目:使用canvas绘画哆啦A梦
  13. tensorflow serving warmup
  14. SSE(Server-sent Events)实现Web消息推送(SpringBoot)
  15. 2020中国机器人公司排行榜TOP10揭晓
  16. 江西伟人系列第三篇:唐宋八大家(欧阳修)
  17. python工作目录是什么意思_Docker的工作目录是什么意思?
  18. r语言中的或怎么表示什么不同_R语言中灵活运用if实现根据不同条件执行不同的语句...
  19. 视频教程-Unity3D实战入门之第三人称射击游戏(TPS)-Unity3D
  20. 我用Python做了个动图生成器,把一千个MM生成了GIF设置桌面,只为每天愉悦心情

热门文章

  1. 网维大师系统虚拟盘控制台 网络中存在另外一台主服务器,网维大师系统虚拟盘性能优化及常见问题...
  2. ESP32 单片机学习笔记 - 03 - MCPWM脉冲输出/PCNT脉冲计数
  3. 2021年全球氯化聚氯乙烯(CPVC)收入大约1809.9百万美元,预计2028年达到3691.5百万美元
  4. Android 音频系统播放延迟时间获取(latency)
  5. EXCLE 制作热力地图、插值图
  6. crc32库 qt_QT实现CRC16校验(查表法)
  7. office 2010 ppt幻灯片自动播放
  8. “./“”@/”“../” 路径问题——我对你知根知底,我劝你放弃抵抗,跟我走一趟
  9. 昆明计算机学校有个爱什么,云南6个爱情传说,总有一个感动你
  10. python解决猴子选大王问题:15个猴子围成一圈选大王,依次1-7循环报数,报到7的猴子被淘汰,直到最后一只猴子成为大王。问: 哪只猴子会成为大王 ?