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

自测之Lesson16:并发通信

知识点:三个多路并发模型(select 、poll 、epoll)

 

题目:以epoll模型,编写一个可供多个客户端访问的服务器程序。

 

实现代码:

#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <sys/epoll.h>
#include <string.h>

#define SRV_PORT 60000
#define BUF_SIZE 1024
#define MAX_CONN 10000000                               // 最大连接数 
#define EVS_LEN  10                                     // epoll_wait()可保存的“收到数据”的fd的最大数目

void startServer()
{
        int iRet;
        char szSnd[BUF_SIZE];
        char szRcv[BUF_SIZE];
        char szBuf[BUF_SIZE];
    
        int fd; 
        fd = socket(PF_INET, SOCK_STREAM, 0); 
        if (fd == -1) {
                perror("fail socket");
                return;
        }

        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(SRV_PORT);
        iRet = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
        if (iRet == -1) {
                perror("fail bind");
                close(fd);
                return;
        }

        listen(fd, MAX_CONN);

/*=========================================== epoll =======================================*/
        int epfd = epoll_create(MAX_CONN);                                      // function 1
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = STDIN_FILENO;
        epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev);                      // function 2
        ev.events = EPOLLIN;
        ev.data.fd = fd;
        epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);

        int clientFd;
        struct sockaddr_in cliAddr;
        socklen_t addrLen = sizeof(cliAddr);
        struct epoll_event evs[EVS_LEN];                                        // 可容纳10个变化的fd
        int cnt;
        while(1) {
                cnt = epoll_wait(epfd, evs, EVS_LEN, -1);                       // function 3
                int i;
                for (i = 0; i < cnt; i++) {
                        if (evs[i].data.fd == fd) {
                                /* new connect */
                                clientFd = accept(fd, (struct sockaddr*)&cliAddr, &addrLen);
                                ev.events = EPOLLIN;
                                ev.data.fd = clientFd;
                                epoll_ctl(epfd, EPOLL_CTL_ADD, clientFd, &ev);
                                printf("New connect from %s:%d\n", inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port));
                                write(clientFd, "Welcome...", 11);
                        }
                        else if (evs[i].data.fd == STDIN_FILENO) {
                                read(STDIN_FILENO, szSnd, BUF_SIZE);
                                printf("command not found\n");
                        }
                        else {
                                memset (szRcv, 0, BUF_SIZE);
                                iRet = read(evs[i].data.fd, szRcv, BUF_SIZE);
                                if (iRet == 0) {
                                        /* 断开连接 */
                                        printf("Disconnect fd:%d\n", evs[i].data.fd);
                                        ev.data.fd = evs[i].data.fd;
                                        epoll_ctl(epfd, EPOLL_CTL_DEL, evs[i].data.fd, NULL);
                                        close(evs[i].data.fd);
                                }
                                else if (iRet < 0) {
                                        perror("fail read");
                                        return;
                                }
                                else {
                                        memset(szBuf, 0, BUF_SIZE);
                                        printf("Recv[%d]:%s\n", evs[i].data.fd, szRcv);
                                        memcpy(szBuf, "I have received!", 17);
                                        write(evs[i].data.fd, szBuf, strlen(szBuf));
                                }

                        }
                }
        }
        close(fd);
        return;
}

int main()
{
        startServer();
        return 0;
}

 

 

题目:以select模型,编写一个可供多个客户端访问的服务器程序。

 

实现代码:

#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

#define SRV_PORT 60000
#define BUF_SIZE 1024
#define MAX_CONN 10000 

void startServer()
{
        int iRet;
        char szSnd[BUF_SIZE];
        char szRcv[BUF_SIZE];
    
        int fd; 
        fd = socket(PF_INET, SOCK_STREAM, 0); 
        if (fd == -1) {
                perror("fail socket");
                return;
        }

        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(SRV_PORT);
        iRet = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
        if (iRet == -1) {
                perror("fail bind");
                close(fd);
                return;
        }

        listen(fd, MAX_CONN);
/**************************************************** select *********************************************************/
        fd_set fdset;
        int i;
        int maxfd = fd;
        int clientFd;
        int fdCnt = 0;                          // 当前连接的客户端数
        int fdArr[MAX_CONN];                    // 存放文件描述符fd的数组
        struct sockaddr_in cliAddr;
        socklen_t addrLen = sizeof(cliAddr);
        while(1) {
                /* select模型每次都要将“fd们”重新加入fdset,开销很大 */
                FD_ZERO(&fdset);
                FD_SET(STDIN_FILENO, &fdset);
                FD_SET(fd, &fdset);
                for (i = 0; i < fdCnt; i++) {
                        FD_SET(fdArr[i], &fdset);       // 将用于和客户端通信的fd都加入fdset
                }

                select(maxfd + 1, &fdset, NULL, NULL, NULL);
                if (FD_ISSET(fd, &fdset)) {
                        clientFd = accept(fd, (struct sockaddr*)&cliAddr, &addrLen);
                        if (fdCnt == MAX_CONN) {
                                printf("Connect over count\n");
                                write(clientFd, "please wait...", 15);
                                close(clientFd);
                        }
                        else {
                                printf("Connect from %s:%d success...\n", inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port));
                                write(clientFd, "Welcome...", 11);
                                fdArr[fdCnt++] = clientFd;
                                if (clientFd > maxfd) {
                                        maxfd = clientFd;       // 更新maxfd
                                }
                        }
                }
                if (FD_ISSET(STDIN_FILENO, &fdset)) {
                        memset(szSnd, 0, BUF_SIZE);
                        read(STDIN_FILENO, szSnd, 1024);
                        printf("command not found\n");
                }
                for (i = 0; i < fdCnt; i++) {
                        if (FD_ISSET(fdArr[i], &fdset)) {
                                memset(szRcv, 0, BUF_SIZE);
                                iRet = read(fdArr[i], szRcv, BUF_SIZE);
                                if (iRet > 0) {
                                        printf("Recv[%d]:%s\n", fdArr[i], szRcv);
                                        write(fdArr[i], "I received!", 12);
                                }
                                else if (iRet == 0) {
                                        close(fdArr[i]);
                                        printf("fd:%d disconnect...\n", fdArr[i]);
                                        int j;
                                        for(j = i; j < fdCnt - 1; j++) {
                                                fdArr[j] = fdArr[j+1];
                                        }
                                        fdCnt--;
                                        i--;
                                }
                                else {
                                        perror("read fail");
                                        return;
                                }
                        }
                }
        }
        return;
}

int main()
{
        startServer();
        return 0;
}

  

小结:epoll模型的优点在于:①对于客户端的数量没有限制;②内核主动将“可读”的fd写入到struct epoll_events数组内,所以节省了poll模型和select模型的每次轮询整个fd集合的开销。

 

转载于:https://www.cnblogs.com/xzxl/p/8575745.html

相关文章:

  • 软工作业PSP与单元测试训练
  • ElasticSearch入门及核心概念介绍
  • 软件工程第二周阅读作业
  • 前台vue的使用简单小结
  • SSRF(服务端请求伪造)
  • ubuntu下unzip解压zip文件中文乱码问题
  • 菜鸟网络与顺丰达成和解 确保数据安全进行合作
  • Android系统启动流程 -- android
  • Exchange 2016 CU9 已发布
  • js上传文件带进度条
  • LinuxUnix命令
  • python——if判断语句的应用
  • Linux学习笔记第三天-软链接和硬链接
  • Linux集群(四)-LVS持久连接与高可用
  • 猜数字小游戏,很naive......
  • 【Linux系统编程】快速查找errno错误码信息
  • HTTP 简介
  • JS学习笔记——闭包
  • quasar-framework cnodejs社区
  • React的组件模式
  • spring security oauth2 password授权模式
  • SSH 免密登录
  • vue.js框架原理浅析
  • 前端
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 微信开放平台全网发布【失败】的几点排查方法
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • #{}和${}的区别是什么 -- java面试
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • (1)(1.9) MSP (version 4.2)
  • (1)虚拟机的安装与使用,linux系统安装
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (bean配置类的注解开发)学习Spring的第十三天
  • (c语言)strcpy函数用法
  • (第61天)多租户架构(CDB/PDB)
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (利用IDEA+Maven)定制属于自己的jar包
  • (七)理解angular中的module和injector,即依赖注入
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转)mysql使用Navicat 导出和导入数据库
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .NET Framework杂记
  • .Net 代码性能 - (1)
  • .Net 应用中使用dot trace进行性能诊断
  • .NET框架