(笔记)第十八节课:wirkshark抓包工具&TCP循环服务器

13 篇文章 1 订阅
9 篇文章 0 订阅

一 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);//清空集合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 256int 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;}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值