嵌入式学习Day36---Linux软件编程---网络编程

news2024/11/30 12:26:00

目录

一、TCP并发模型

1.1.阻塞IO

1.2.非阻塞IO

1.步骤

2.函数接口

3.实例

1.3.异步IO

1.步骤

2.函数接口

3.实例

1.4.多路复用IO 

1.select

函数接口:

实例 

2.poll

3.epoll

 二、总结


 

一、TCP并发模型

1.1.阻塞IO

 CPU占用率低,等待资源时将任务挂起,不占用CPU资源,等到拿到资源后继续向下执行;

1.2.非阻塞IO

 能够让任务不阻塞,效率低,因为没有数据时,CPU一直空转;

1.步骤

        1)获取文件描述符的IO状态

        2)设置文件描述符的IO状态为非阻塞

        3) 将该IO状态写入文件描述符

2.函数接口

        fctnl() 具体使用看下面的例子

3.实例

        此处,以写入端通过管道向接收端传递信息,接收端可以接收管道信息,并且也可以从终端接收。将管道和终端的描述符均设置为非阻塞,实现,接收端一边可以接收写入端的信息,一边可以接收终的信息。(核心在read.c)

write.c

#include "../head.h"

int main(void)
{
    int fd = 0;
    int ret = 0;
    ssize_t nsize = 0;
    char buff[1024] = {0};
    mkfifo("/tmp/myfifo", 0664);
    

    fd = open("/tmp/myfifo", O_WRONLY);
    if (fd == -1)
    {
        perror("open");
        return -1;
    }

    while(1)
    {
        memset(buff, 0, sizeof(buff));
        gets(buff);
        nsize = write(fd, buff, strlen(buff)+1);
        if (nsize == -1)
        {
            perror("write");
            return -1;
        }

    }
    

    close(fd);

    return 0;
}

 read.c

#include "../head.h"

int main(void)
{   
    int fd = 0;
    int flag = 0;
    ssize_t nsize = 0;
    char *pnisze = NULL;
    char buf[1024] = {0};

    mkfifo("/tmp/myfifo", 0664);
    fd = open("/tmp/myfifo", O_RDONLY);
    if (-1 == fd)
    {
        perror("fail to open");
        return -1;
    }


    //获得文件描述符的熟悉
    flag = fcntl(fd, F_GETFL);
    //设置文件描述符为非阻塞
    flag |= O_NONBLOCK;
    //设置文件描述符
    fcntl(fd, F_SETFL, flag);

    /*设置终端IO*/
    flag = fcntl(0, F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(0, F_SETFL, flag);

    while (1)
    {
        memset(buf, 0, sizeof(buf));
        nsize = read(fd, buf, sizeof(buf));
        if (nsize > 0)
        {
            printf("WRITE = %s\n", buf);
        }

        memset(buf, 0, sizeof(buf));
        pnisze = gets(buf);
        if (pnisze != NULL)
        {
            printf("STDIN = %s\n", buf);
        }

    }

    close(fd);
    
    return 0;
}

1.3.异步IO

        将一个文件描述符设定为异步IO,当IO有事件发生时,内核会向用户层发送SIGIO信号提醒用户层处理事件  

1.步骤

        1)获取文件描述符的IO状态

        2)设置文件描述符的IO状态为异步

        3) 将该IO状态写入文件描述符

        4)处理IO信号

2.函数接口

        fctnl() 具体使用看下面的例子

        signal(SIGIO, handel); 接收文件描述符信号 

3.实例

        此处,以写入端通过管道向接收端传递信息,接收端可以接收管道信息,并且也可以从终端接收。将管道描述符设置为异步,终端信息正常接收,当管道里面有了一个信息时,发送SIGIO信号。(核心在read.c)

write.c

#include "../head.h"

int main(void)
{
    int fd = 0;
    int ret = 0;
    ssize_t nsize = 0;
    char buff[1024] = {0};
    mkfifo("/tmp/myfifo", 0664);
    

    fd = open("/tmp/myfifo", O_WRONLY);
    if (fd == -1)
    {
        perror("open");
        return -1;
    }

    while(1)
    {
        memset(buff, 0, sizeof(buff));
        gets(buff);
        nsize = write(fd, buff, strlen(buff)+1);
        if (nsize == -1)
        {
            perror("write");
            return -1;
        }

    }
    

    close(fd);

    return 0;
}

read.c

#include "../head.h"

int fd = 0;
void handler(int sig)
{

    char tmpbuff[1024] = {0};

    memset(tmpbuff, 0, sizeof(tmpbuff));
    read(fd, tmpbuff, sizeof(tmpbuff));
    printf("RECV:%s\n", tmpbuff);
}
int main(void)
{   

    int flag = 0;
    ssize_t nsize = 0;
    char *pnisze = NULL;
    char buf[1024] = {0};

    mkfifo("/tmp/myfifo", 0664);
    fd = open("/tmp/myfifo", O_RDONLY);
    if (-1 == fd)
    {
        perror("fail to open");
        return -1;
    }

    //获取管道的IO状态
    flag = fcntl(fd, F_GETFL);
    //设置为异步
    flag |= O_ASYNC;
    fcntl(fd, F_SETFL, flag);
    //通知当前进程管道信号来了
    fcntl(fd, F_SETOWN, getpid());

    signal(SIGIO, handler);



    while (1)
    {

        memset(buf, 0, sizeof(buf));
        pnisze = gets(buf);
        if (pnisze != NULL)
        {
            printf("STDIN = %s\n", buf);
        }


    }



    close(fd);


    return 0;
}

 

1.4.多路复用IO 

1.select

函数接口:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
          功能:
            监听文件描述符是否有事件发生
          参数:
            nfds:最大文件描述符的值 + 1 
            readfds:读文件描述符集合
            writefds:写文件描述符集合
            exceptfds:异常文件描述符集合
            timeout:超时时间
          返回值:
            成功返回产生事件的文件描述符个数
            失败返回-1 
            timeout时间到达仍然没有产生的事件返回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);
        功能:将文件描述符集合清0 
实例 

client.c

#include "head.h"

int CreateTcpConnection(const char *pip, int port)
{
    int sockfd = 0;
    int ret = 0;
    struct sockaddr_in seraddr;
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(port);
    seraddr.sin_addr.s_addr = inet_addr(pip);

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
    {
        return -1;
    }

    ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
    if (-1 == ret)
    {
        return -1;
    }

    return sockfd;
}

int HandleConnection(int sockfd)
{
    char tmpbuff[4096] = {0};
    static int cnt = 0;
    ssize_t nsize = 0;

    sprintf(tmpbuff, "hello world --- %d", cnt);
    nsize = send(sockfd, tmpbuff, strlen(tmpbuff), 0);
    if (-1 == nsize)
    {
        return -1;
    }
    cnt++;

    memset(tmpbuff, 0, sizeof(tmpbuff));
    nsize = recv(sockfd, tmpbuff, sizeof(tmpbuff), 0);  
    if (-1 == nsize)
    {
        return -1;
    }
    else if (0 == nsize)
    {
        return 0;
    }
    
    printf("RECV:%s\n", tmpbuff);

    return nsize;
}

int main(void)
{
    int sockfd = 0;
    int ret = 0;

    sockfd = CreateTcpConnection(SER_IP, SER_PORT);
    if (-1 == sockfd)
    {
        printf("连接服务器异常\n");
        return -1;
    }

    while (1)
    {
        ret = HandleConnection(sockfd);
        if (-1 == ret)
        {
            printf("连接出错!\n");
            break;
        }
        else if (0 == ret)
        {
            printf("连接关闭\n");
            break;
        }

        sleep(1);
    }
    
    close(sockfd);

    return 0;
}

server.c

#include "head.h"

int CreateListenSocket(const char *pip, int port)
{
    int sockfd = 0;
    int ret = 0;
    struct sockaddr_in seraddr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
    {
        return -1;
    }

    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(port);
    seraddr.sin_addr.s_addr = inet_addr(pip);
    ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
    if (-1 == ret)
    {
        return -1;
    }

    ret = listen(sockfd, 10);
    if (-1 == ret)
    {
        return -1;
    }

    return sockfd;
}

int HandleConnection(int confd)
{
    char tmpbuff[4096] = {0};
    ssize_t nsize = 0;

    nsize = recv(confd, tmpbuff, sizeof(tmpbuff), 0);
    if (-1 == nsize)
    {
        return -1;
    }
    else if (0 == nsize)
    {
        return 0;
    }

    printf("RECV:%s\n", tmpbuff);

    sprintf(tmpbuff, "%s --- echo", tmpbuff);

    nsize = send(confd, tmpbuff, strlen(tmpbuff), 0);
    if (-1 == nsize)
    {
        return -1;
    }

    return nsize;
}

int main(void)
{
    int sockfd = 0;
    int confd = 0;
    int ret = 0;
    fd_set rdfds;
    fd_set tmpfds;
    int nready = 0;
    int maxfd = 0;
    int i = 0;

    //创建监听套接字
    sockfd = CreateListenSocket(SER_IP, SER_PORT);
    if (-1 == sockfd)
    {
        printf("创建监听套接字失败\n");
        return -1;
    }

    //将sockfd加入监听集合中
    FD_ZERO(&rdfds);
    FD_SET(sockfd, &rdfds);
    maxfd = sockfd;

    while (1)
    {
        //开始监听
        tmpfds = rdfds;
        nready = select(maxfd+1, &tmpfds, NULL, NULL, NULL);
        if (-1 == nready)
        {
            perror("fail to select");
            return -1;
        }

        //如果sockfd产生事件,处理新的连接请求,并将新的文件描述符加入集合,下次一起监听
        if (FD_ISSET(sockfd, &tmpfds))
        {
            confd = accept(sockfd, NULL, NULL);
            if (-1 == confd)
            {
                FD_CLR(sockfd, &rdfds);
                close(sockfd);
                continue;
            }   

            maxfd = maxfd > confd ? maxfd : confd;
            FD_SET(confd, &rdfds);
        }

        //遍历所有已经连接的客户端中是否有事件发生
        for (i = sockfd+1; i <= maxfd; i++)
        {
            if (FD_ISSET(i, &tmpfds))
            {
                ret = HandleConnection(i);
                if (-1 == ret)
                {
                    printf("连接异常\n");
                    FD_CLR(i, &rdfds);
                    close(i);
                    continue;
                }
                else if (0 == ret)
                {
                    printf("连接断开\n");
                    FD_CLR(i, &rdfds);
                    close(i);
                    continue;
                }
            }
        }
    }
    
    close(sockfd);

    return 0;
}

2.poll

3.epoll

 二、总结

        2024年8月20日,学习的第36天。今天主要学习TCP的并发模型,主要学习如何模拟实现现实中统一服务器可以和好多不同的客户端同时交互。

        加油!

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

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

相关文章

初识指针5の学习笔记

目录 1>>前言 2>>qsort函数的实现 2.1>>什么时qsort函数&#xff1f; 2.2>>qsort函数的格式是什么&#xff1f; 2.3>>qsort函数的解析 2.4>>qsort函数的实现&#xff01; 3>>结语 1>>前言 今天我会继续分享一些我做的笔…

大模型基础学习知识,看这一篇就够了

​ 学习路线&#xff1a;感性认识现象->理解本质和原理->将所学知识用于解释新现象并指导实践。 ​ LLM训练模型的的三个阶段&#xff1a; 1、Pre-train 2、Supervised Fine-Tuning&#xff1a;Instruction Fine-tuning 3、RLHF - > RLAIF&#xff1a;增强式学习…

Internet Download Manager(下载工具)中文授权版

IDM是一款windows平台下的下载工具。 软件截图&#xff1a; 使用说明&#xff1a; 解压后&#xff0c;双击start_IDM.bat来运行软件 下载地址&#xff1a; IDM-v6.42.20-Repack 解压密码&#xff1a;helloh 下载时可能会有广告&#xff0c;忽略&#xff0c;等下载结束即可…

IM 旗舰版、IM 尊享版计费说明(海外 - 北美数据中心)

本文档详细描述了适用于使用海外北美数据中心 App 的 IM 旗舰版、IM 尊享版计费套餐及相应增值服务项目的计费细则。 本文档中采用人民币定价&#xff0c;价格仅适用于以人民币结算的服务订单。如果您使用非人民币结算&#xff0c;请咨询相关商务人员。 The English version o…

React 使用ref属性调用子组件方法(也可以适用于父子传参)

注意&#xff1a;①需使用hooks函数组件 ②使用了antDesign组件库&#xff08;可不用&#xff09; 如何使用 父组件代码 import React, { useState, useRef, useEffect } from react; import { Button } from antd; import Child from ./components/child;export defau…

华为面试题就这?24岁的我直接拿下28K的offer...

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 先说一下我的情况&#xff0c;某普通本科计算机&#xff0c;之前在深圳那边做了大约半年多少儿编程老师&#xff0c;之后内部平调回长沙这边&#xff0c;回来之后发…

LLaVA 简介:一种多模式 AI 模型

LLaVA 是一个端到端训练的大型多模态模型&#xff0c;旨在根据视觉输入&#xff08;图像&#xff09;和文本指令理解和生成内容。它结合了视觉编码器和语言模型的功能来处理和响应多模态输入。 图 1&#xff1a;LLaVA 工作原理的示例。 LLaVA 的输入和输出&#xff1a;连接视觉…

大型语言模型(LLM)历史简介

在 DALL-E 2 中生成的图像。 介绍 当我们谈论大型语言模型 (LLM) 时&#xff0c;我们实际上指的是一种能够以类似人类的方式进行交流的高级软件。这些模型具有理解复杂上下文并生成连贯且具有人情味的内容的惊人能力。 如果您曾经与 AI 聊天机器人或虚拟助手聊天&#xff0c…

搜维尔科技:【研究】Haption Virtuose外科手术触觉视觉学习系统的开发和评估

Haption面临挑战 除此之外&#xff0c;外科医生有时会对骨组织进行非常复杂的手术&#xff0c;其中一个例子是人工耳蜗的手术植入。重要的是要避免神经或血管等危险结构受伤&#xff0c;并尽可能轻柔地进行手术。在外科医生能够安全、无差错地进行此类手术之前&#xff0c;需要…

WKWebView加载项目中网页的资源图片路径异常

问题原因&#xff0c;将含有html的文件通过如下方式引入到工程中&#xff1a; 这种处理方式&#xff0c;当应用程序变以后&#xff0c;引入的文件会被全部放在Resources目录下&#xff0c;而忽略你原本的文件路径信息。因此导致出问题。 解决方案&#xff1a; 采用如下方式引…

输入一个列表,返回手动反转后的新列表

import math def deverseHanshu(*nums):listAlist(nums)for i in range(0,math.ceil(len(listA)/2)): #math.ceil(3.14) #4clistA[-(i1)]listA[-(i1)]listA[i]listA[i]creturn listA print(deverseHanshu(45,3,89,45,56,2,22,10))#方法2 def getReverse(listAttr):resultList[…

第133天:内网安全-横向移动域控提权NetLogonADCSPACKDC永恒之蓝

案例一&#xff1a;横向移动-系统漏洞-CVE-2017-0146 这个漏洞就是大家熟悉的ms17-010&#xff0c;这里主要学习cs发送到msf&#xff0c;并且msf正向连接后续 原因是cs只能支持漏洞检测&#xff0c;而msf上有很多exp可以利用 注意msf不能使用4.5版本的有bug 这里还是反弹权…

国自然放榜在即!用这种方法或可抢先查询...

【SciencePub学术】本期热点 国自然 昨日国自然网站提示&#xff1a;系统将于8月20日12:00-12:30进行维护&#xff0c;请您避开该时间段使用&#xff0c;由此给您造成的不便&#xff0c;敬请谅解。 根据往年的经验&#xff0c;这预示着基金评审结果即将公布&#xff0c;应该就…

Apache Dolphinscheduler Standalone 部署教程

Standalone 仅适用于 DolphinScheduler 的快速体验. 如果你是新手&#xff0c;想要体验 DolphinScheduler 的功能&#xff0c;推荐使用Standalone方式体检。 如果你想体验更完整的功能&#xff0c;或者更大的任务量&#xff0c;推荐使用伪集群部署。如果你是在生产中使用&…

安卓开发:基础返回按钮代码

我们在大部分页面都会配一个返回按钮。虽然实现起来非常简单&#xff0c;但是很多开发者不想动这个脑筋。这边给出通用的基础代码&#xff0c;可以直接复制粘贴使用。 <androidx.appcompat.widget.Toolbarandroid:id"id/<>"android:layout_height"wra…

Java中“final、finally、finalize”三者的区别

Java中的"final"、"finally"和"finalize"是三个不同的关键字&#xff0c;它们各自有不同的用途和含义&#xff1a; 1. final - 用于声明一个变量、方法或类是不可变的。 - 被声明为final的变量一旦被初始化后&#xff0c;其值不能被改变。 …

5、并发锁机制之synchronized

并发锁机制之synchronized i/i--引起的线程安全问题分析原因分析i的JVM字节码指令i--的JVM 字节码指令结论 解决方案 synchronized的使用加锁方式使用synchronized解决之前的共享问题方式一方式二 synchronized底层实现原理分析查看synchronized的字节码指令序列重量级锁实现之…

国富基金入股的关联性与奇瑞依赖症,大昌科技业务独立性引关注

《港湾商业观察》廖紫雯 日前&#xff0c;安徽大昌科技有限公司&#xff08;以下简称&#xff1a;大昌科技&#xff09;更新招股书并完成三轮问询&#xff0c;公司冲刺深交所创业板得到进一步进展。此前&#xff0c;2023年6月&#xff0c;大昌科技IPO获深交所受理&#xff0c;…

Qt使用开发板上的按键-思维导图-学习笔记-基于正点原子阿尔法开发板

Qt使用开发板上的按键 出厂内核设备树中注册的按键 I.MX6U设备树路径为arch/arm/boot/dts/imx6ull-14x14-evk.dts 如何看这个按键的键值对应键盘中的按键 键值宏定义是在<linux/input.h>头文件中 资源简介 ALPHA 开发板的 KEY0 按键原理图 应用实例 按键注册 正点…

浅谈【网络编程】之Unix与多路复用

目录 1、Unix域协议 2、多路复用 select poll / epol 谢谢帅气美丽且优秀的你看完我的文章还要点赞、收藏加关注 没错&#xff0c;说的就是你&#xff0c;不用再怀疑&#xff01;&#xff01;&#xff01; 希望我的文章内容能对你有帮助&#xff0c;一起努力吧&#xff01;…