C++linux高并发服务器项目实践 day3

文件IO

内存===文件
从文件到内存为I
从内存到文件为O

标准C库IO函数与LinuxIO函数

标准C库IO函数
在这里插入图片描述

man 3 fopen
可以打开linux的操作手册关于fopen的相关资料

同样的

man 3 fwrite

linux自带的读写,使用一次就会读一次或写一次磁盘,效率其实不如c标准库的高

在这里插入图片描述

在vscode中,写入FILE,ctrl加左键可以进入他的定义,发现他的原型是_IO_FILE,再次ctrl加左键,发现该结构体中,有char*类型的各个变量用于读写和缓冲

虚拟地址空间

在这里插入图片描述
只有实际内存空间会出现的问题:

  1. 当剩余内存不足以跑下一个程序时,运行会失败
  2. 当前面的程序释放后,虽然剩余空间能跑下一个程序,但是内存是分割开的

利用MMU(内存管理单元)来进行虚拟内存和物理内存之间的管理和转换

文件描述符

在Linux的内核区,有一个PCB(进程控制块),可以控制文件描述符
文件描述符存储在文件描述符表内,文件描述符表在数据结构上是数组形式,表的默认大小为1024
在这里插入图片描述
文件描述符表的前三位是固定的
就是标准输入、标准输出、标准错误,默认是打开状态
/dev/tty 通过上述3位可以找到当前绑定的设备终端
他们对应的终端是同一个
一个文件能被打开多次,但是多次打开的文件描述符是不一样的
在fopen打开一个文件时,一个文件描述符被占用,只有将其fclose或以linux内部的close关闭后,这个文件描述符才能再次启用
内核会自己寻找空闲的最小的文件描述符

Linux系统IO函数

int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_t mode);
int close(int fd);
ssize_t read(int fd,void *buf,size_t count);
ssize_t write(int fd,const void *buf,size_t count);
off_t lseek(int fd,off_t offset,int whence);
int stat(const char *pathname.struct stat *statbuf);
int lstat(const char *pathname,struct stat *statbuf);

open与close

虽然函数重载是c++的内容,但是上述函数是C语言的,所以两个open其实是采用可变参数的方式实现的

open函数的声明在fcntl.h这个头文件内,open内部的flags定义了一些宏,放到另外两个头文件中

第一个open函数用于打开一个已经存在的文件
int open(const char *pathname,int flags);
参数:

  • pathname:要打开的文件路径
  • flags:对文件的操作权限及其他设置
    O_RDONLY,O_WRONLY,O_RDWR 这三个设置是互斥的

返回值:

  • 返回一个新的文件描述符,如果调用失败,返回-1

errno:属于Liux系统函数库,库里面的一个全局变量,记录的是最近的错误号

/*
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>

    //打开一个已经存在的文件
    int open(const char *pathname, int flags);
        参数:
            - pathname:要打开的文件路径
            - flags:对文件的操作权限及其他设置
                O_RDONLY,O_WRONLY,O_RDWR  这三个设置是互斥的
        返回值:返回一个新的文件描述符,如果调用失败,返回-1
    errno:属于Liux系统函数库,库里面的一个全局变量,记录的是最近的错误号

    #include <stdio.h>
    void perror(const char *s);
        s参数:用户描述,比如hello,最终输出的内容是 hello:xxx(实际错误描述)

    作用:打印errno对应的错误描述

    //创建一个新的文件
    int open(const char *pathname, int flags, mode_t mode);

    #include <unistd.h>

    int close(int fd);


*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main(){

    int fd = open("a.txt",O_RDONLY);

    if(fd == -1){
        perror("open");
    }

    //关闭
    close(fd);

    return 0;
}

第二个open函数用于创建一个新的文件
int open(const char *pathname,int flags,mode_t mode);
参数:

  • pathname:要打开的文件路径

  • flags:对文件的操作权限及其他设置
    - 必选项:O_RDONLY,O_WRONLY,O_RDWR
    - 可选项:O_CREAT 文件不存在创建文件

  • mode:八进制的数,表示用户对创建出的新的文件的操作权限
    最终的权限是:mode & ~umask
    0777 r(读) w(写) x(可执行)都有这样的权限即都是1,换算成8进制就是7
    三个7分别代表当前用户,当前用户所在组的权限,其他组的权限
    可以通过umask来查询本机的umask的值是多少
    我这里查到的是0002取反后为0775
    0777 -> 11111111
    & 0775 -> 11111101

            11111101
    

    按位与:0和任何数都为0
    umask的作用就是抹去某些权限

    可以用umask 后面跟上数值来修改例如 umask 022
    但是这个修改只能作用在本窗口,新开一个窗口就会失效

read和write

read:
头文件: #include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
参数:

  • fd:文件描述符,open得到的,通过这个文件描述符操作某个文件
  • buf:需要读取数据存放的缓冲区,数组的地址(传出参数)
  • count:指定的数组的大小

返回值:

  • 成功:
    》0:返回实际的读取到的字节数
    =0:文件已经读取完了
  • 失败: -1,并且设置errno

write:
头文件: #include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
参数:

  • fd:文件描述符,open得到的,通过这个文件描述符操作某个文件
  • buf:要往磁盘写入的数据,数组
  • count:要写的数据的实际的大小

返回值:

  • 成功:实际写入的字节数
  • 失败:返回-1,并且设置errno
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    //1.通过open打开english.txt文件
    int srcfd = open("english.txt",O_RDONLY);
    if(srcfd == -1){
        perror("open");
        return -1;
    }

    //2.创建一个新的文件(拷贝文件)
    int destfd = open("cpy.txt",O_WRONLY|O_CREAT,0664);
    if(destfd == -1){
        perror("open");
        return -1;
    }

    //3.频繁的读写操作
    char buf[1024] = {0};

    int len = 0;
    while(( len = read(srcfd,buf,sizeof(buf))) > 0){
        write(destfd,buf,len);
    }
    

    //4.关闭文件
    close(destfd);
    close(srcfd);

    return 0;
}

lseek函数

标准C库的函数
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);

Linux系统函数
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
第一个头文件放了一些宏定义,第二个头文件是unix的标准头文件

参数:

  • fd:文件描述符,通过open得到的,通过这个fd操作某个文件
  • offset:偏移量
  • whence:
    SEEK_SET:设置文件指针的偏移量
    SEEK_CUR:设置偏移量:当前位置+第二个参数offset的值
    SEEK_END:设置偏移量:文件大小+第二个参数offset的值

作用:

  1. 移动文件指针到头文件
    lseek(fd,0,SEEK_SET);

  2. 获取当前文件指针的位置
    lseek(fd,0,SEEK_CUR);

  3. 获取文件长度
    lseek(fd,0,SEEK_END);

  4. 拓展文件的长度,当前文件10b,110b,增加了100个字节
    lseek(fd,100,SEEK_END);
    注意:需要写一次数据

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(){
    int fd = open("hello.txt",O_RDWR);

    if(fd == -1){
        perror("open");
        return -1;
    }

    //扩展文件的长度
    int ret = lseek(fd,100,SEEK_END);
    if(ret == -1)
    {
        perror("lseek");
        return -1;
    }

    //写入一个空数据
    write(fd," ",1);

    //关闭文件
    close(fd);

    return 0;
}

stat与lstat

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *statbuf);

作用:获取一个文件相关的一些信息
参数:

  • pathname:操作的文件的路径
  • statbuf:结构体变量,传出参数,用于保存获取到的文件的信息

返回值:

  • 成功:返回0
  • 失败:返回-1,设置errno

int lstat(const char *pathname, struct stat *statbuf);

作用:获取软链接文件本身的信息
参数:

  • pathname:操作的文件的路径
  • statbuf:结构体变量,传出参数,用于保存获取到的文件的信息
    返回值:
  • 成功:返回0
  • 失败:返回-1,设置errno
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>

int main(){
    struct stat statbuf;
    
    int ret = stat("a.txt",&statbuf);

    if(ret == -1){
        perror("stat");
        return -1;
    }

    printf("size:%ld\n",statbuf.st_size);

    return 0;
}

在这里插入图片描述
在这里插入图片描述

stat a.txt

可以查看a的一些信息

ln -s a.txt b.txt

创建一个软链接文件b.txt指向a.txt
若这里使用stat访问b.txt,则实际访问的是a.txt的信息
若想要访问b.txt本身,则需要lstat

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
高性能并发服务器项目实战是指在实际项目中开发和部署能够处理高并发请求的服务器。在这个项目中,我们需要考虑到服务器的性能和并发处理能力。 首先,我们需要选择适合的服务器框架和编程语言,例如Java或C++。这些语言具有较高的性能和并发处理能力,可以满足大量请求的需求。 其次,我们需要进行服务器的优化和扩展设计。可以通过使用多线程、线程池、异步IO等技术来提高服务器的并发处理能力。同时,还需要考虑服务器的物理资源和网络带宽等因素,以确保服务器能够支持高并发量。 然后,我们需要对服务器进行压力测试和性能优化。可以使用工具,如JMeter或wrk来模拟大量并发请求,并监测服务器的性能指标,如吞吐量、响应时间等。通过分析测试结果,我们可以找出性能瓶颈并进行相应的优化,如代码优化、数据库优化、缓存策略等。 最后,我们需要进行服务器集群和负载均衡的部署。通过将服务器部署在多台机器上,并使用负载均衡器来分发请求,可以进一步提高服务器的性能和可扩展性。同时,还需要考虑服务器的容灾和备份策略,以确保系统的高可用性和可靠性。 总之,高性能并发服务器项目实战是一个综合性的项目,需要综合考虑多个因素,包括服务器框架的选择、优化设计、性能测试与优化、集群部署等。只有通过不断的实践和优化,才能够开发出满足高并发请求的高性能服务器

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值