Linux 学习记录33(网络编程篇)

news2024/11/16 11:25:45

Linux 学习记录33(网络编程篇)

在这里插入图片描述

本文目录

  • Linux 学习记录33(网络编程篇)
  • 一、阻塞IO
  • 二、非阻塞IO
  • 三、信号驱动IO
  • 四、`IO多路复用(重点)`
    • 1. select (TCP服务器)
      • TCP服务器代码
      • TCP客户端代码
    • 2. poll

一、阻塞IO

1. 最常用,最简单,效率最低的.
2. 创建套接字文件描述符后,默认处于阻塞IO模式
3.  read, write, recv, send, recvfrom ,sendto,accept

二、非阻塞IO

1. 防止进程阻塞在IO函数上,但是如果想要获取到有效数据,需要轮询。
2. 当一个程序使用了非阻塞10模式的套接字,那么它需要使用一个循环来不停的判断该文件描述符是否有数据可读,称之为polling
3. 应用程序不停的polling内核监测IO事件是否产生,cpu消耗率高
4. IO中导致函数阻塞的原因是因为文件描述符有阻塞属性
头文件:
#include <fcntl.h> 包含文件的属性
函数:
int fcntl(int fd, int cmd, ... /* arg */ );
功能:获取/设置文件描述符属性
	1. 获取原有属性
	2. 在原有属性的基础上 加上非阻塞属性
	3. 将修改后的属性重新设置到文件描述符上
参数1:指定要设置的文件描述符
参数2:参数
	F_GETFD (void) :获取文件属性,数值
	F_SETFD (int) :设置文件属性权限,要设置的权限放在第三个参数传入
参数3:要设置的文件描述符属性
===================================================================
/*获取原有文件属性*/
int flags = fcntl(0, F_GETFL);
/*添加非阻塞属性*/
flags |= O_NONBLOCK;
/*设置文件描述符属性*/
fcntl(0, F_SETFL ,flags);

三、信号驱动IO

1. 异步通信方式;
2. 信号驱动IO是指预先告诉内核,使得某个文件描述符发生I0事件的时候,内核会通知相关进程:SIGIO
3. 对于TCP而言,信号驱动IO对TCP没有用。因为信号产生过于频繁,而且不能区分是哪个文件描述符发生的。

四、IO多路复用(重点)

所需头文件:#include <sys/select.h>

  1. 进程中如果同时需要处理多路输入输出流,在使用单进程单线程的情况下,同时处理多个输入输出请求。
  2. 在无法用多进程多线程,可以选择用IO多路复用;
  3. 由于不需要创建新的进程和线程,减少系统的资源开销,减少上下文切换的次数
  1. 上下文: 运行一个进程所需要的所有资源
  2. 上下文切换: 从A进程切换到B进程,A进程的资源要完全替换成B进程的,是一个耗时操作
  1. 允许同时对多个IO进行操作,内核一旦发现进程执行一个或多个IO事件,会通知该进程

1. select (TCP服务器)

函数原型:int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
功能:
	若集合中有文件描述符准备就绪,则select解除阻塞后,集合中会只剩下触发事件的文件描述符。
参数1:三个集合中最大的文件描述符+1
参数2:读集合
参数3:写集合
参数4:其他集合
参数5:超时间,若不想设置填NULL,则直到文件描述符准备就绪结束阻塞
返回值:
	大于0:成功触发的文件描述符的个数
	等于0:时间结束
	小于0:失败
==============================================================================
操作集合的函数
void FD_CLR(int fd,fd_set *set);将fd从集合中删除
int FD_ISSET(int fd,fd set *set);判断fd是否在集合中,若存在返回真,否则返回假;
void FD_SET(int fd, fd set *set);将fd设置到集合中
void FD_ZERO(fd, set *set);清空集合

TCP服务器代码

int main(int argc, char const *argv[])
{
    int i=0;
    time_t sys_t = time(NULL);
    struct tm *fomattime = localtime(&sys_t);
    char time_str[50] = {0};

    /*创建流式套接字*/
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    const int sfd_const = sfd;
    printf("创建流式套接字...\r\n");
    if(sfd < 0)
    {//如果创建失败则
        ERR_MSG("socket");
        return -1;
    }
    printf("创建成功\r\n");

    /*允许端口被快速重用*/
    int reuse = 1;
    if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)))
    {
        ERR_MSG("setsockopt");
        return -1;
    }

    /*绑定服务器的IP和端口*/
    struct sockaddr_in sin_addr;//定义本机通用地址信息结构体
    char TCP_ADDR[20] = {0};//存放本机IP
    int port = 0;
    sin_addr.sin_family = AF_INET;//必须填AF_INET
    printf("input address : ");
    fgets(TCP_ADDR,sizeof(TCP_ADDR),stdin);//获取IP
    printf("input port : ");
    scanf("%d",&port);//获取端口号
    sin_addr.sin_port = htons(port);//端口号
    sin_addr.sin_addr.s_addr = inet_addr(TCP_ADDR);//填充IP地址
    printf("绑定服务器IP和端口......\r\n");
    if(bind(sfd,(const struct sockaddr*)&sin_addr,sizeof(sin_addr))<0)
    {
        ERR_MSG("bind");
        return -1;
    }
    printf("绑定成功\r\n");

    /*将套接字设定为被动监听状态*/
    printf("设置监听模式\r\n");
    if(listen(sfd,BACKLOG) == -1)
    {
        ERR_MSG("listen");
        return -1;
    }
    printf("设置完成\r\n");
    printf("等待客户端链接......\r\n");

    /*获取链接成功后的与客户端通信的套接字文件描述符s*/
    struct sockaddr_in addr;//存储客户端的地址信息
    socklen_t addr_len;
    int newfd;
    addr_len = sizeof(addr);

    /*创建要监测的集合*/
    fd_set readfds;
    fd_set buffds;

    char buf[1024];
    /*接收来自客户端的数据*/
    char str[128] = {0};
    int res = 0;
    int s_res = 0;
    int max_fd = sfd;
    cilent_t* cilent = (cilent_t*)malloc(sizeof(cilent_t)*1024);
    
    /*清空集合*/
    FD_ZERO(&readfds);
    FD_ZERO(&buffds);
    /*将文件描述符设置到集合内*/
    FD_SET(0,&buffds);
    FD_SET(sfd,&buffds);

    while(1)
    {
        /*重新赋值IO集合*/
        readfds = buffds;
        /*阻塞等待IO触发*/
        s_res = select(max_fd+1, &readfds,NULL,NULL,NULL);
        if(s_res == -1)
        {
            return -1;
        }else if(s_res == 0)
        {
            return 0;
        }
        /*运行到此则表示有文件描述符被触发*/
        /*需要判断是哪个文件描述符准备就绪*/
        /*只需要判断集合中剩下那几个文件描述符,就代表该文件描述符有事件产生*/
        /*判断是否有接收客户端数据客户端*/
        for(i = 0; i <= max_fd; i++)
        {
            if(!FD_ISSET(i,&readfds))
            continue;

            if(i == 0)
            {
                fgets(buf, sizeof(buf),stdin);
                buf[sizeof(buf)-1] = '\0';
                GET_TIME(time_str);//获取时间戳
                TCP_printf(newfd,"%s : stdin>> %s",time_str,buf);
            }else if(i == sfd)
            {
                if((i = accept(sfd,(struct sockaddr*)&addr,&addr_len)) == -1)
                {
                    ERR_MSG("accept");
                    return -1;
                }
                strcpy(cilent[i].cil_IP,inet_ntoa(addr.sin_addr));
                cilent[i].port=ntohs(addr.sin_port);
                printf("客户端已链接\r\n");
                printf("客户端IP : %s\r\n",cilent[i].cil_IP);
                printf("客户端端口 : %d\r\n",cilent[i].port);
                /*更新文件描述符到集合中*/
                FD_SET(i,&buffds);
                /*更新最大文件描述符值*/
                max_fd = max_fd>i?max_fd:i;
            }else
            {
                bzero(str,sizeof(str));//清空字符串
                res = recv(i,str,sizeof(str),0);//阻塞接收字符串
                if(res == -1)
                {
                    perror("recv");
                }else if(res == 0)
                {
                    printf("客户端关闭{%s:%d}\r\n",cilent[i].cil_IP,cilent[i].port);
                    close(i);//关闭文件描述符
                    FD_CLR(i,&readfds);
                    /*更新最大文件描述符值*/
                    int j = max_fd;
                    while(!FD_ISSET(j,&readfds)&&j-->=0);
                    max_fd = j;
                    continue; 
                }else
                {
                    GET_TIME(time_str);//获取时间戳
                    TCP_printf(i,"%s : cilent{%s:%d}>> %s\r\n",time_str,cilent[i].cil_IP,cilent[i].port,str);
                }
            }
        }
    }

    close(sfd);//关闭套接字文件

    return 0;
}

TCP客户端代码

#include "public.h"

int main(int argc, char const *argv[])
{
    time_t sys_t = time(NULL);
    struct tm *fomattime = localtime(&sys_t);
    char time_str[50] = {0};

    /*创建流式套接字*/
    int cfd = socket(AF_INET, SOCK_STREAM, 0);
    printf("创建流式套接字...\r\n");
    if(cfd < 0)
    {//如果创建失败则
        ERR_MSG("socket");
        return -1;
    }
    printf("创建成功\r\n");

    /*连接服务器*/
    struct sockaddr_in cin_addr;//定义本机通用地址信息结构体
    cin_addr.sin_family = AF_INET;//必须填AF_INET
    char TCP_ADDR[20] = {0};//存放服务器IP
    int TCP_PORT = 0;
    printf("input address : ");
    fgets(TCP_ADDR,sizeof(TCP_ADDR),stdin);//获取IP
    printf("input port : ");
    scanf("%d",&TCP_PORT);//获取端口号
    cin_addr.sin_port = htons(TCP_PORT);//端口号
    cin_addr.sin_addr.s_addr = inet_addr(TCP_ADDR);//填充IP地址
    printf("连接服务器......\r\n");
    if(connect(cfd,(const struct sockaddr*)&cin_addr,sizeof(cin_addr)) == -1)//链接服务器
    {
        ERR_MSG("connect");
        return -1;
    }
    printf("服务器连接完成\r\n");

    /*接收来自服务器的数据*/
    char str[128] = {0};
    char buf[128] = {0};
    int flage = 0;
    int res = 0;
    printf("接收服务器数据\r\n");

    int s_res = 0;
    /*创建要监测的集合*/
    fd_set readfds;
    fd_set buffds;
    /*集合清零*/
    FD_ZERO(&readfds);
    FD_ZERO(&buffds);
    /*集合设置*/
    FD_SET(0, &buffds);//设置终端
    FD_SET(cfd, &buffds);//设置通讯文件描述符

    while (1)
    {
        readfds = buffds;
        /*阻塞等待IO更新*/
        s_res = select(cfd+1, &readfds, NULL,NULL,NULL);
        if(s_res == -1)
        {
            return -1;
        }else if(s_res == 0)
        {
            return 0;
        }
        /*当终端更新*/
        if(FD_ISSET(0, &readfds))
        {
            fgets(buf, sizeof(buf),stdin);
            buf[sizeof(buf)-1] = '\0';
            send(cfd,buf,sizeof(buf),0);
        }
        //当文件更新
        if(FD_ISSET(cfd, &readfds))
        {
            res = recv(cfd,str,sizeof(str),0);
            if(res == -1)
            {
                perror("recv");
                return 0;
            }else if(res == 0)
            {
                printf("服务器关闭\r\n");
                break;
            }else
            {
                GET_TIME(time_str);//获取时间戳
                printf("%s : server{%s:%d}>> %s\r\n",time_str,inet_ntoa(cin_addr.sin_addr),ntohs(cin_addr.sin_port),str);
            }
        }
    }

    close(cfd);//关闭套接字文件
    return 0;
}

2. poll

所需头文件:#include <poll.h>

函数原型:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
功能:阻塞函数,让内核监测集合中是否有文件描述符准备就绪,若准备就绪,则立即解除阻塞;
参数1:文件描述符集合
	struct pollfd {
       int   fd;         /* file descriptor */     指定要监测的文件描述符
        short events;     /* requested events */    指定要监测的事件
        short revents;    /* returned events */     实际产生的事件
    };
    事件:
    1. POLLIN:读事件
    2. POLLOUT:写事件
    3. POLLERR:错误事件
参数2:指定要监测的文件描述符个数
参数3:超时时间
	>0, 设置超时时间,以ms为单位
	=0, 非阻塞,会立即解除阻塞
	<0, 阻塞,直到有文件描述符准备就绪,解除阻塞
返回值:
	>0, 成功触发事件的文件描述符个数;
    =0, 超时;
    =-1, 函数运行失败

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

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

相关文章

WPF开发txt阅读器11:自定义控件更改音量语速

文章目录 自定义控件控件调用自定义事件更改音量和语速 txt阅读器系列&#xff1a; 需求分析和文件读写目录提取类&#x1f48e;列表控件与目录字体控件绑定&#x1f48e;前景/背景颜色书籍管理系统&#x1f48e;用树形图管理书籍语音播放&#x1f48e;播放进度显示&#x1f4…

【Java】Java核心要点总结 65:TreeSet 两种排序

文章目录 1. Comparable 和 Comparator区别比较2. TreeSet有两种实现指定排序规则的方式&#xff1a; 1. Comparable 和 Comparator区别比较 Comparable 是排序接口&#xff0c;若一个类实现了Comparable接口&#xff0c;就意味着“该类支持排序”。Comparator 是比较器&#x…

使用post请求建立长连接实现sse,接收后端主动发来的消息,实现chat-gpt的弹字效果,EventSource的应用

每日鸡汤&#xff1a;每个你想要学习的瞬间都是未来的你向自己求救 最近在做一个chat相关的功能&#xff0c;然后由于接口返回特别特别慢&#xff0c;所以需要搞一个慢慢等待的效果&#xff0c;就是接口一个单词一个单词的返回&#xff0c;然后前端收到一个展示一个&#xff0c…

Nucleo-F411RE (STM32F411)LL库体验 6 - EXTI外部中断的使用

Nucleo-F411RE &#xff08;STM32F411&#xff09;LL库体验 6 - EXTI外部中断的使用 1、简述 开发板蓝色按键连接PC13管脚&#xff0c;且断开时为高电平&#xff0c;闭合时低电平。我们将pc13设置为中断模式&#xff0c;低电平触发&#xff0c;当按键按下时&#xff0c;触发中…

Hadoop完全分布式运行环境的搭建

Hadoop完全分布式运行环境的搭建 文章目录 Hadoop完全分布式运行环境的搭建0. 写在前面1. 模板虚拟机环境准备安装模板虚拟机hadoop01虚拟机配置要求如下关闭防火墙&#xff0c;关闭防火墙开机自启创建普通用户配置新用户权限修改所属主和所属组卸载虚拟机自带的JDK重启虚拟机 …

【备战秋招】每日一题:4月23日美团春招第四题:题面+题目思路 + C++/python/js/Go/java带注释

为了更好的阅读体检&#xff0c;为了更好的阅读体检&#xff0c;&#xff0c;可以查看我的算法学习博客第四题-01串的代价 在线评测链接:P1248 题目内容 塔子哥是一个喜欢研究密码的人&#xff0c;他经常在网上寻找各种有趣的密码挑战。他最近发现了一个神秘的网站&#xff…

指定字符串数组中每个元素sn的长度L如果sn长度比L短,则补充空格,且sn居中如果sn长度比L长,则保留sn左侧L个字符

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 指定字符串数组中每个元素sn的长度L 如果sn长度比L短&#xff0c;则补充空格,且sn居中 如果sn长度比L长&#xff0c;则保留sn左侧L个字符 [太阳]选择题 下列代码最后输出的结果是&#xff1f…

基于Java在线购物系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

MindFusion.Java Swing Pack 2023.R1 Crack

MindFusion.Java Swing Pack 2023.R1 改进了图表、电子表格和虚拟键盘。 6月 15&#xff0c; 2023 - 16&#xff1a;06 新版本 特征 MindFusion.Diagramming 的新功能 空间索引 - 创建项目位置索引&#xff0c;以便更快地进行命中测试和视口裁剪查询。这极大地提高了包含数…

ch8_1_CPU的结构和功能

1. cpu的结构 1.1CPU 的功能 控制器的功能 控制器的功能具体作用取指令指令控制分析指令操作控制执行指令&#xff0c; 发出各种操作命令控制程序输入与结果的输出时间控制总线管理处理中断处理异常情况和特殊请求数据加工 运算器的功能 实现算术运算 和 逻辑运算&#x…

基于Java多角色学生管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

基于Java网上服装销售系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

【大数据】可视化仪表板 - Superset的安装和使用

写在前面&#xff1a;博主是一只经过实战开发历练后投身培训事业的“小山猪”&#xff0c;昵称取自动画片《狮子王》中的“彭彭”&#xff0c;总是以乐观、积极的心态对待周边的事物。本人的技术路线从Java全栈工程师一路奔向大数据开发、数据挖掘领域&#xff0c;如今终有小成…

11-高性能JSON库——fastjson2

目录 1.具体使用 1.1.添加fastjson2依赖 1.2.常用类和方法 1.3.将JSON字符串转换成对象 1.3.1.JSON字符串转换成对象 1.3.2.JSON字符串转换成数组 1.4.将对象转换成JSON字符串 1.4.1.将对象转换成JSON字符串 1.4.2.将数组转换成 JSON 字符串 2.性能测试报告 3.总结 …

浪潮发布G2平台

2017年2月28日下午&#xff0c;浪潮在北京粤财JW万豪酒店以“智变”为主题&#xff0c;发布新一代智能存储平台G2&#xff0c;该平台基于统一架构和In系列智能软件设计&#xff0c;在保障”三高”特性满足企业级关键数据存储、处理需求的同时&#xff0c;更强调数据生命周期的智…

第六章 部署WSUS及RDS服务

❄️作者介绍&#xff1a;奇妙的大歪❄️ &#x1f380;个人名言&#xff1a;但行前路&#xff0c;不负韶华&#xff01;&#x1f380; &#x1f43d;个人简介&#xff1a;云计算网络运维专业人员&#x1f43d; 前言 适用范围&#xff1a;Windows Server 2022、Windows Server…

揭密ChatGPT背后团队鲜为人知的小秘密

ChatGPT引领的人工智能技术浪潮还在持续火爆&#xff0c;可是做出这款产品的OpenAI公司&#xff0c;熬得住多年的冷板凳&#xff0c;最终一飞冲天&#xff0c;他们是怎么做到的呢&#xff1f; 因此&#xff0c;我对这家企业的组织建设产生了浓厚的兴趣。我找啊找&#xff0c;最…

游戏开发日志13(利用PlayerPrefs来存储数据)

为游戏设置一个音量键&#xff0c;可以自由选择背景音乐是否开启&#xff0c;并且保存这个设置。 设计了UI如下&#xff1a; 其中BGM为Toggle&#xff0c;其余四个为Button 在canvas&#xff08;set&#xff09;上添加两个脚本&#xff1a;GameMnue&#xff0c;GameManage p…

【备战秋招】每日一题:4月15日美团春招第三题:题面+题目思路 + C++/python/js/Go/java带注释

为了更好的阅读体检&#xff0c;为了更好的阅读体检&#xff0c;&#xff0c;可以查看我的算法学习博客第三题-交通规划 在线评测链接:P1237 题目内容 塔子哥所在的国家有 n 个城市&#xff0c;这 n 个城市排成一列&#xff0c;按顺序编号为 1,2,3,...,n。然而&#xff0c;由…

【备战秋招】每日一题:4月8日美团春招第五题:题面+题目思路 + C++/python/js/Go/java带注释

为了更好的阅读体检&#xff0c;为了更好的阅读体检&#xff0c;&#xff0c;可以查看我的算法学习博客第五题-RGP种树 在线评测链接:P1170 题目描述&#xff1a; 塔子哥是一位著名的冒险家&#xff0c;他经常在各种森林里探险。今天&#xff0c;他来到了道成林&#xff0c;…