C++基于select和epoll的TCP服务器

select版本

服务器

#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <string>
#include <pthread.h>
#include <sys/select.h>
#include <stdio.h>
int main()
{
    int flag=0;
    struct sockaddr_in saddr;
    saddr.sin_port = htons(8999);
    saddr.sin_addr.s_addr = INADDR_ANY;
    saddr.sin_family = AF_INET;
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sfd == -1)
    {
        perror("socket error");
        return 1;
    }
    int optvalue;
    setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, &optvalue,sizeof(int));//设置端口复用
    flag = bind(sfd, (struct sockaddr*)&saddr, sizeof(struct sockaddr_in));
    if (flag == -1)
    {
        perror("bind error");
        return 1;
    }
    flag=listen(sfd, 100);
    if(flag==-1)
    {
        perror("listen error");
        return 1;
    }
    fd_set readset,tmp;
    FD_ZERO(&readset);
    FD_SET(sfd,&readset);
    int nfds=sfd;
    while (1)
    {
        tmp=readset;//每一次tmp的值都会被内核修改,所以要用readset重制
        flag=select(nfds+1,&tmp,NULL,NULL,NULL);//异常和写集合一般不检测
        if(flag==-1)
        {
            perror("select error");
            continue;
        }
        for(int i=sfd;i<=nfds;i++)//i可以从0开始,但是会做几次多余判断
        {
            int port;
            if(i==sfd&&FD_ISSET(i,&tmp))//判断监听套接字是否满足条件
            {
                struct sockaddr_in caddr;
                int clen=sizeof(caddr);
                int cfd = accept(sfd, (struct sockaddr*)&caddr, (socklen_t*)&clen);
                port=ntohs(caddr.sin_port);
                if (cfd == -1)
                {
                    perror("accept error");
                    continue;
                }
                char ip[1024]={'\0'};//必须加上,不然解析IP会失败
                printf("接收到了客户端%s:%d的连接\n",inet_ntop(AF_INET,&caddr.sin_addr,ip,1024),port);
                FD_SET(cfd,&readset);//将通信套接字加入文件描述符表
                nfds=nfds>cfd?nfds:cfd;//更新ndfs
            }
            else//判断是否有满足条件的通信套接字
            {
                if(FD_ISSET(i,&tmp))
                {
                    char buf[1024] = {'\0'};
                    flag = recv(i, buf, 1024, 0);
                    if (flag==-1)
                    {
                        perror("read error");
                        break;
                    }
                    else if(flag==0)
                    {
                        printf("连接断开\n");
                        FD_CLR(i,&readset);
                        close(i);
                    }
                    else
                    {
                        printf("从客户端收到数据:%s\n",buf);
                        std::string sendstr="服务器收到了"+std::to_string(port)+"的数据";
                        flag = send(i, sendstr.c_str(), sendstr.length(), 0);
                        if (flag == -1)
                        {
                            perror("send error");
                        }
                        memset(buf, 0, 1024);
                    }
                }
            }
        }
    }
    close(sfd);
    return 0;
}

客户端

#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <string>

int main()
{
    int flag;
    struct sockaddr_in* caddr=(struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
    inet_pton(AF_INET, "192.168.101.231", &caddr->sin_addr.s_addr);
    caddr->sin_family = AF_INET;
    caddr->sin_port = htons(8999);
    int cfd = socket(AF_INET, SOCK_STREAM, 0);
    if (cfd == -1)
    {
        perror("socket error");
        return 1;
    }
    int addrlen=sizeof(struct sockaddr);
    int i=0;
    flag= connect(cfd, (struct sockaddr*)caddr, addrlen);//caddr就是指针类型
    if (flag == -1)
    {
        perror("connect error");
        return 1;
    }
    while(1)
    {
        char buf[1024] = {'\0'};
        std::string sendstr="我是客户端"+std::to_string(getpid())+"发送了数据"+std::to_string(i);
        flag = send(cfd,  sendstr.c_str(), sendstr.length(),0);
        if (flag == -1)
        {
            perror("send error");
            continue;
        }
        printf("send:%s\n", sendstr.c_str());
        flag = recv(cfd, buf, 1024, 0);
        if (flag == -1)
        {
            perror("recv error");
            continue;
        }
        printf("客户端收到数据:%s\n", buf);
        memset(buf, 0, 1024);
        i++;
        sleep(1);
    }
    close(cfd);
    return 0;
}

epoll

服务器

#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <string>
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
int main()
{
    int flag=0;
    struct sockaddr_in saddr;
    saddr.sin_port = htons(8999);
    saddr.sin_addr.s_addr = INADDR_ANY;
    saddr.sin_family = AF_INET;
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sfd == -1)
    {
        perror("socket error");
        return 1;
    }
    int optvalue;
    setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, &optvalue,sizeof(int));//设置端口复用
    flag = bind(sfd, (struct sockaddr*)&saddr, sizeof(struct sockaddr_in));
    if (flag == -1)
    {
        perror("bind error");
        return 1;
    }
    flag=listen(sfd, 100);
    if(flag==-1)
    {
        perror("listen error");
        return 1;
    }
    int epfd=epoll_create(1);
    struct epoll_event ev;
    ev.data.fd=sfd;
    ev.events=EPOLLIN|EPOLLET;
    flag=epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&ev);
    struct epoll_event revents[1024];
    while (1)
    {

        int num=epoll_wait(epfd,revents,1024,-1);
        if(num==-1)
        {
            perror("epoll wait error");
            continue;
        }
        for(int i=0;i<num;i++)
        {
            int port;
            int curfd=revents[i].data.fd;
            if(curfd==sfd)//判断监听套接字是否满足条件
            {
                struct sockaddr_in caddr;
                int clen=sizeof(caddr);
                int cfd = accept(sfd, (struct sockaddr*)&caddr, (socklen_t*)&clen);
                port=ntohs(caddr.sin_port);
                if (cfd == -1)
                {
                    perror("accept error");
                    continue;
                }
                int attr=fcntl(cfd,F_GETFL);//获取文件描述符的属性
                attr|=O_NONBLOCK;//用位等于给文件添加属性
                fcntl(cfd,F_SETFL,attr);//添加属性非阻塞
                char ip[1024]={'\0'};//必须加上,不然解析IP会失败
                printf("接收到了客户端%s:%d的连接\n",inet_ntop(AF_INET,&caddr.sin_addr,ip,1024),port);
                ev.data.fd=cfd;
                ev.events=EPOLLIN|EPOLLET;
                epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&ev);
            }
            else//判断是否有满足条件的通信套接字
            {
                char buf[5] = {'\0'};
                while(1)
                {
                    int num = recv(curfd, buf, 5, 0);
                    if (num==-1)
                    {
                        if(errno==EAGAIN)
                        {
                            printf("数据读取完毕");
                        }
                        else
                        {
                            perror("recv error");
                        }
                        break;
                    }
                    else if(num==0)
                    {
                        printf("连接断开\n");
                        epoll_ctl(epfd,EPOLL_CTL_DEL,curfd,NULL);
                        close(curfd);
                        break;
                    }
                    else
                    {
                        printf("从客户端收到数据:%s\n",buf);
                        char sendbuf[1024]={"服务器收到了客户端的数据:"};
                        strcat(sendbuf,buf);
                        flag = send(curfd, sendbuf,strlen(sendbuf), 0);
                        if (flag == -1)
                        {
                            perror("send error");
                        }
                        memset(sendbuf, 0, 1024);
                    }
                    memset(buf, 0, 5);
                }
            }
        }
    }
    close(sfd);
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言零基础入门篇 - 7】:拆解函数的奥秘:定义、声明、变量,传递须知,嵌套玩转,递归惊艳

文章目录 函数函数的定义与声明局部变量和全局变量、静态变量静态变量和动态变量函数的值传递函数参数的地址传值 函数的嵌套使用函数的递归调用 函数 函数的定义与声明 函数的概念&#xff1a;函数是C语言项目的基本组成单位。实现一个功能可以封装一个函数来实现。定义函数的…

Qt 菜单栏、工具栏、状态栏、标签、铆接部件(浮动窗口) 设置窗口核心部件(文本编辑控件)的基本使用

效果 代码 #include "mainwindow.h" #include "ui_mainwindow.h" #include<QToolBar> #include<QDebug> #include<QPushButton> #include<QStatusBar> #include<QLabel> #include<QDockWidget> #include<QTextEdi…

MySQL权限控制(DCL)

我的mysql里面的一些数据库和一些表 基本语法 1.查询权限 show grants for 用户名主机名;例子1&#xff1a;查询权限 show grants for heima%;2.授予权限 grant 权限列表 on 数据库名.表名 to 用户名主机名;例子2&#xff1a; 授予权限 grant all on itcast.* to heima%;…

低代码门户技术:构建高效应用的全新方式

什么是低代码门户技术&#xff1f; 低代码门户技术是一种利用低代码平台构建企业门户网站或应用的技术。门户通常是企业内部和外部用户访问信息和应用的集中平台。低代码门户技术通过图形化界面和预置组件&#xff0c;允许用户快速搭建和定制这些门户平台&#xff0c;而无需深…

HTTPS:构建安全通信的基石

HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;&#xff0c;作为互联网上安全通信的基石&#xff0c;通过在HTTP基础上引入SSL/TLS协议层&#xff0c;实现了数据传输的加密&#xff0c;确保了信息的机密性、完整性和真实性。这一过程涉及多个精细设计的步骤…

初始网络编程(下)

所属专栏&#xff1a;Java学习 1. TCP 的简单示例 同时&#xff0c;由于 TCP 是面向字节流的传输&#xff0c;所以说传输的基本单位是字节&#xff0c;接受发送都是使用的字节流 方法签名 方法说明 Socket accept() 开始监听指定端口&#xff08;创建时绑定的端口&…

git安装包夸克网盘下载

git安装包夸克网盘下载 git夸克网盘 git网站上的安装包下载速度有点慢&#xff0c;因此为了方便以后下载就将文件保存到夸克网盘上&#xff0c;链接&#xff1a;我用夸克网盘分享了「git」&#xff0c;点击链接即可保存。 链接&#xff1a;https://pan.quark.cn/s/07c73c4a30…

外网(公网)访问VMware workstation 虚拟机内web网站的配置方法---端口转发总是不成功的原因

问题背景&#xff1a;客户提供的服务器操作系统配置web程序时&#xff0c;总是显示莫名其妙的问题&#xff0c;发现是高版本操作系统的.net库已经对低版本.net库进行了大范围修订&#xff0c;导致在安全检测上、软件代码规范上更加苛刻&#xff0c;最终导致部署不成功。于是想到…

【Linux课程学习】make/Makefile:Linux项目自动化构建工具

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux课程学习 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 &#x1f349;一.make/Makefile的理解&#xff1a; …

掌握 Spring:从新手到高手的常见问题汇总

一提起Spring&#xff0c;总感觉有太多知识&#xff0c;无法详尽&#xff0c;有些基础理解就先不说了&#xff0c;相信大家都已经用过Spring了 下面简单针对常见Spring面试题做些回答 核心特性 IOC容器spring事件资源管理国际化校验数据绑定类型转换spirng表达式面向切面编程……

【HTTP】构造HTTP请求和状态码

状态码 用于响应中&#xff0c;表示响应的结果如何 正确&#xff1f;错误&#xff1f;什么原因&#xff1f; HTTP 中的状态码都是标准约定好的 200 OK 成功了&#xff0c;一切顺利 在抓包到的响应中 404 Not Found 访问的资源&#xff08;URL 中的路径&#xff09;没找…

Python语言基础教程(下)4.0

✨博客主页&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客内容》&#xff1a;.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 &#x1f4e2;博客专栏&#xff1a; https://blog.csdn.net/m0_63815035/cat…

十六 未来信息综合技术(考点篇)

1 信息物理系统技术 信息物理系统(CPS)是控制系统、嵌入式系统的扩展与延伸&#xff0c;其涉及的相关底层理论技术源于对嵌入式技术的应用与提升。 CPS 通过集成先进的感知、计算、通信、控制等信息技术和自动控制技术&#xff0c;构建了物理空间与信息空间中人、机、物、环境…

OpenCV特征检测(3)计算图像中每个像素处的特征值和特征向量函数cornerEigenValsAndVecs()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算图像块的特征值和特征向量用于角点检测。 对于每一个像素 p &#xff0c;函数 cornerEigenValsAndVecs 考虑一个 blockSize blockSize 的邻…

mysql为什么建议创建字段的时候not null

相信大家在建表或者给表新加字段的时候&#xff0c;一些老司机们都会建议我们&#xff0c;字段要定义为not null&#xff0c;原因呢是一是占用存储空间&#xff0c;另一个是避免出现一些意料之外的错误。当然针对这个问题&#xff0c;大家可能也会在网上去搜下&#xff0c;不过…

制作炫酷个人网页:用 HTML 和 CSS3 展现你的风格

你是否觉得自己的网站应该看起来更炫酷&#xff1f;今天我将教你如何使用 HTML 和 CSS3 制作一个拥有炫酷动画和现代设计风格的个人网页&#xff0c;让它在任何设备上看起来都无敌酷炫&#xff01; 哈哈哈哈哈哈哈哈,我感觉自己有点中二哈哈哈哈~ 目录 炫酷设计理念构建 HTML …

【电力系统】基于遗传算法的33节点电力系统无功优化及MATLAB实现

摘要 本文研究了基于遗传算法的33节点配电系统的无功优化问题。通过调整电容器的安装位置和容量&#xff0c;以最小化系统的无功损耗和电压偏差。研究使用遗传算法对无功优化问题进行求解&#xff0c;并在MATLAB环境中进行仿真实现。实验结果表明&#xff0c;该方法能够有效地…

零工市场小程序:推动零工市场建设

人力资源和社会保障部在2024年4月发布了标题为《地方推进零工市场建设经验做法》的文章。 零工市场小程序的功能 信息登记与发布 精准匹配、推送 在线沟通 权益保障 零工市场小程序作为一个找零工的渠道&#xff0c;在往后随着技术的发展和政策的支持下&#xff0c;功能必然…

★ C++进阶篇 ★ 二叉搜索树

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将继续和大家一起学习C进阶篇第三章----二叉搜索树 ~ ❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️ 澄岚主页&#xff1a;椎名澄嵐-CSDN博客 C基础篇专栏&#xff1a;★ C基础篇 ★_椎名澄嵐的博客-CSD…

【matlab】生成 GIF 的函数(已封装可直接调用)

文章目录 前言一、函数输入与输出二、函数代码三、例程&#xff08;可直接运行&#xff09;参考文献 前言 生成 gif 图片时遇到的问题&#xff0c;为了后续调用方便&#xff0c;封装为函数 一、函数输入与输出 输入&#xff1a; cell_figure: cell 数组&#xff0c;数组元素是…