IPv4流媒体广播项目-项目分析

在这里插入图片描述服务端

  1. 多线程或多进程并发
  2. 引入数据库或者使用当前文件系统
    解析文件系统存储
  3. 流量控制
  4. 网络套接字socket
  5. 应为守护进程,脱离终端,IO重定向,系统日志

客户端

  1. 父进程,从网络上接收数据,传递给子进程
  2. 子进程,接收数据并播放
  3. 父、子进程实现及其关系
  4. 进程通信

参考资料
《UNIX环境高级编程(第3版)》
《UNIX网络编程》
《TCP/IP详解(卷一)》
《深入理解计算机系统》

学习方法介绍

  • 纸上得来终觉浅,绝知此事要躬行
IO
	第3、5章节

文件系统
	第4、6、7章节
	
并发
	第8、10、11章节
	多进程并发(信号)第10章
	多线程并发第10、11章节

IPC 进程间通信
	进程基础(涉及多进程)第8章
	守护进程		第13章
	进程间通信	第15、16章节

注意事项:

  1. 弃用root用户
  2. 对代码进行重构
  3. 课堂重点:项目,课堂代码,面试题,实验性题目,推荐书籍的课后习题

I/O,input & output,是一切实现的基础。

stdio	标准IO
sysio	系统调用IO(文件IO)

在这里插入图片描述优先考虑标准I/O

标准IO

stdio: man 3

fopen();	文件打开
fclose();	文件关闭
fgetc();	读取字符
fputc();	写字符
fgets();	读取字符串
fputs();	写字符串
fread();	读二进制
fwrite();	写二进制

printf()族
scanf()族

fseek();
ftell();
rewind();

fflush();

标准IO相关结构体FILE

man fopen

       #include <stdio.h>

       FILE *fopen(const char *pathname, const char *mode);
       参数:
       		pathname,文件路径名
       		mode,打开模式
       			r,只读打开,文件指针在beginning of file (不会创建)
       			r+,读写打开,文件指针在文件开始处	(不会创建)
       			w,只写形式打开,有则清空,无则创建,文件指针在文件开始处(文件的第一个有效字节)
       			w+,读写形式打开,有则清空,无则创建,文件指针在文件开始处(文件的第一个有效字节)
       			a,追加写(只有追加写,没有追加读),文件最后一个有效字节的下一个位置(end of file)
       			a+,以读写(追加写)形式打开文件,无则创建,
       						读:beginning of file,即 文件的第一个有效字节
       						追加写:end of file,即文件最后一个有效字节的下一个位
       						注意:区分文件最后一个有效字节与最后一个有效字节的下一个位置
       			b,二进制,Windows区分字符与二进制
       			注意,r和r+ 要求文件必须存在,否则结束当前调用,返回错误
       返回值:
       		成功:FILE指针
       		失败:NULL,errno(errno是全局变量?)

errno定义的位置:

cat /usr/include/asm-generic/errno.h
cat /usr/include/asm-generic/errno-base.h

面试题

已知条件:
	char *ptr="abc"; //字符串常量
	ptr[0]='x';
问:是否会得到"xbc"?
答:取决于当前平台使用的编译器会把"abc"放到哪里存储?

编程tips

int *p = malloc(sizeof(int));
malloc的返回值是void *
如果不添加头文件#include<stdlib.h>,
gcc会认为所有函数的返回值是int(有例外),将int型赋值给int *必然会报错

补充函数perror与strerror

man perror
	perror - print a system error message
	
man strerror
	#include <string.h>
	char *strerror(int errnum);  //return string describing error number

打开不同的注释,观察执行结果

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int

main (){
        FILE *fp;
        fp= fopen("tmp","r");
        if(fp==NULL){
                //fprintf(stderr,"fopen error! errno= %d \n",errno);
                perror("fopen()");
                //fprintf(stderr,"fopen():%s\n",strerror(errno));
                exit(1);
        }
        puts("fopen OK!");
        exit(0);
}

思考:

 FILE *fopen(const char *pathname, const char *mode);
调用fopen返回的FIEL结构体保存在哪里?
1. 栈?
2. 静态区?
3. 堆?
	FILE *fopen(const char *pathname, const char *mode);
	{
		FILE tmp; //局部变量??  ❌
		tmp.xx=uu;
		...
		return tmp;
		----------------------------------------
		static FILE tmp; //静态区?? ❌ 后打开的会覆盖先打开的
		tmp.xx=vv;
		...
		return tmp;
		----------------------------------------
		FILE *tmp = NULL; //放在堆??  ✔
		tmp = malloc (sizeof FILE); //
		tmp->xx=ww;
		...
		return &tmp;
	}
	fopen fclose
	//如果一个函数的返回值是指针,并且该函数有一个逆操作,通常这样的函数的返回值指针存储在堆上

函数fclose

man fclose
       fclose - close a stream  关闭流
       #include <stdio.h> //头文件
       int fclose(FILE *stream); //函数原型
  1. 谁打开谁关闭
  2. 谁申请谁释放
  3. 是资源就有上限

在不更改当前默认环境的情况下,一个进程默认打开3个stream流:
可通过ulimit -a查看,通过ulimit -n xxx更改对应的值

  1. stdin
  2. stdout
  3. stderr
user@ubuntu:~/codes$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 15374
max locked memory       (kbytes, -l) 65536
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 15374
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

文件权限(以umask=0002为例)

0666 & ~umask
	110 110 110   ---0666
	000 000 010   ---0002
0666 与umask取反相与
	111 111 101  ---~umask
	110 110 110  ---0666
	110 110 100  ---0666 & ~umask 相与的结果
	即664  rw-rw-r--
lry@ubuntu:~/codes$ ll tmp
-rw-rw-r-- 1 lry lry 0 9月  30 23:16 tmp

2021/10/1

fgetc、fputc

  1. 凡是返回值是指针,要思考指向的内容存储在哪个地方。
  2. 宏只占用编译时间,不占用调用时间,函数则恰恰相反
       #include <stdio.h>
       int fgetc(FILE *stream); // input of characters and strings
       int fputc(int c, FILE *stream);  // output of characters and strings

cp命令demo

建议先关闭依赖其他文件的文件

#include <stdlib.h>
#include <stdio.h>

int main(int argc,char **argv){

        int ch;
        FILE *src_file=NULL;
        FILE *dst_file=NULL;

        //too few arguments
        if(argc<3){
                fprintf(stderr,"Usage: %s <src_file> <dst_file> \n",argv[0]);
                exit(1);
        }

        //open source file
        src_file=fopen(argv[1],"r");
        if(src_file==NULL){
                perror("error to open src file");
                exit(1);
        }

        //open destination file
        dst_file=fopen(argv[2],"w");
        if(dst_file==NULL){
                perror("error to open dst file");
                fclose(src_file); //avoid out of memory
                exit(1);
        }

        //loop for  copy
        while(1){

                ch=fgetc(src_file);
                printf("%3d----%c\n",ch,ch+'\0');//for debug
                if(ch==EOF)
                        break;
                fputc(ch,dst_file);
        }

        //close files opened
        fclose(dst_file);
        fclose(src_file);

        exit(0);
}

统计文件有效字符个数,即文件大小size

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char **argv){

        int counter=0;
        FILE * fp=NULL;

        if(argc<2){
                fprintf(stderr,"Usage: %s <file>\n",argv[0]);
                exit(1);
        }

        fp=fopen(argv[1],"r");
        if(fp==NULL){
                perror("fopen error!");
                exit(1);
        }

        while(fgetc(fp)!=EOF){
                counter++;
        }

        printf("count=%d\n",counter);

        fclose(fp);
        exit(1);

}

函数fgets、 fputs

函数原型

man fgets
	char *fgets(char *s, int size, FILE *stream); //从stream中读取size-1个有效字节,放到s指向的地方
man fputs
	int fputs(const char *s, FILE *stream);
	int puts(const char *s);

fgets正常结束的两种情况

  1. 读取了size-1个有效字节,剩下一个字节是留给补全为0的
  2. 读取到'\n'
    即使是最后一行,行尾也会有换行\n
例如文件的最后一行为:
ab
实际读取的内容
'a' 'b' '\n' '\0'

请看下图:
在这里插入图片描述基于fgets fputs实现的cp


#include <stdlib.h>
#include <stdio.h>
#define BUFSIZE 1024

int main(int argc,char **argv){

        char buf[BUFSIZE];
        FILE *src_file=NULL;
        FILE *dst_file=NULL;

        //too few arguments
        if(argc<3){
                fprintf(stderr,"Usage: %s <src_file> <dst_file>",argv[0]);
                exit(1);
        }

        //open source file
        src_file=fopen(argv[1],"r");
        if(src_file==NULL){
                perror("error to open src file");
                exit(1);
        }

        //open destination file
        dst_file=fopen(argv[2],"w");
        if(dst_file==NULL){
                perror("error to open dst file");
                fclose(src_file); //avoid out of memory
                exit(1);
        }

        //loop for  copy
        while(fgets(buf,BUFSIZE,src_file)!=NULL)
                fputs(buf,dst_file);


        //close files opened
        fclose(dst_file);
        fclose(src_file);

        exit(0);
}

标题函数fread fwrite

NAME
       fread, fwrite - binary stream input/output

SYNOPSIS
       #include <stdio.h>

       size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

       size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
RETURN VALUE
	On  success, fread() and fwrite() return the number of items read or written

编程tips:推荐使用1字节读取

fread (buf, size, nmemb, fp);
1. 数量足够
fread( buf, 1, 10 ,fp ); //读10个1字节,返回值10
fread( buf, 10, 1, fp );//读1个10字节,返回值10
2. 只有5个字节
fread( buf, 1, 10 ,fp ); //读5个1字节, 返回值5
fread( buf, 10, 1, fp );//读不到1个10字节,不知道读了多少字节(1-9),返回值0

基于fread fwrite实现的cp

#include <stdlib.h>
#include <stdio.h>
#define BUFSIZE 1024

int main(int argc,char **argv){

        int n=0;
        char buf[BUFSIZE];
        FILE *src_file=NULL;
        FILE *dst_file=NULL;

        //too few arguments
        if(argc<3){
                fprintf(stderr,"Usage: %s <src_file> <dst_file>",argv[0]);
                exit(1);
        }

        //open source file
        src_file=fopen(argv[1],"r");
        if(src_file==NULL){
                perror("error to open src file");
                exit(1);
        }

        //open destination file
        dst_file=fopen(argv[2],"w");
        if(dst_file==NULL){
                perror("error to open dst file");
                fclose(src_file); //avoid out of memory
                exit(1);
        }

        //loop for  copy
        while((n=fread(buf,1,BUFSIZE,src_file))>0)
                fwrite(buf,1,n,dst_file);


        //close files opened
        fclose(dst_file);
        fclose(src_file);

        exit(0);
}

函数fprintf族

man fprintf
		#include <stdio.h>
       int printf(const char *format, ...);
       int fprintf(FILE *stream, const char *format, ...);
       int dprintf(int fd, const char *format, ...);
       int sprintf(char *str, const char *format, ...); //atoi的反向功能
       int snprintf(char *str, size_t size, const char *format, ...);

man atoi
NAME
       atoi, atol, atoll - convert a string to an integer

SYNOPSIS
       #include <stdlib.h>

       int atoi(const char *nptr);
       long atol(const char *nptr);
       long long atoll(const char *nptr);

示例

#include <stdio.h>
#include <stdlib.h>

int main(){

        char buf[1024];
        int year=2021,month=5,day=13;

        sprintf(buf,"%d-%d-%d",year,month,day);
        puts(buf);

        //char str[]="123a456";
        //printf("%d\n",atoi(str));//atoi() ends with 'a'
        //
        exit(1);
}

函数sprintf族

       #include <stdio.h>
       int scanf(const char *format, ...);
       int fscanf(FILE *stream, const char *format, ...);
       int sscanf(const char *str, const char *format, ...);

       #include <stdarg.h>
       int vscanf(const char *format, va_list ap);
       int vsscanf(const char *str, const char *format, va_list ap);
       int vfscanf(FILE *stream, const char *format, va_list ap);

函数fseek ftell

man fseek
NAME
       fgetpos, fseek, fsetpos, ftell, rewind - reposition a stream
SYNOPSIS
	   #include <stdio.h>
       int fseek(FILE *stream, long offset, int whence); //offset   -2G~2G
       long ftell(FILE *stream); //返回值0-2G
       void rewind(FILE *stream);

函数fseeko ftello

NAME
       fseeko, ftello - seek to or report file position
SYNOPSIS
       #include <stdio.h>
       int fseeko(FILE *stream, off_t offset, int whence);
       off_t ftello(FILE *stream);

文件指针操作

man fseek
NAME
       fgetpos, fseek, fsetpos, ftell, rewind - reposition a stream 重新定位流

SYNOPSIS
       #include <stdio.h>

       int fseek(FILE *stream, long offset, int whence);
       		stream,
       		offset,偏移量
       		whence,相对位置,SEEK_SET, SEEK_CUR , SEEK_END

       long ftell(FILE *stream); //返回当前文件指针所在的位置

       void rewind(FILE *stream); //相当于(void) fseek(stream, 0L, SEEK_SET)

标题计算文件大小

fp=fopen(argv[1] , "r" );
fseek(fp , 0,SEEK_END);
printf("%ld \n", ftell(fp));

空洞文件 '\0' 或者asci码为0

缓冲区的作用

  1. 合并系统调用
  2. 行缓冲,①换行时刷新②满的时候刷新③强制刷新(fflush、标准输出)
  3. 全缓冲,①满的时候刷新②强制刷新(默认,只要不是终端设备)
  4. 无缓冲,需要立即输出的内容,如stderr
  5. setvbuf,更爱缓冲模式
  The setvbuf() function may be used on any open stream to change its buffer.  The mode argument must  be  one
       of the following three macros:

              _IONBF unbuffered

              _IOLBF line buffered

              _IOFBF fully buffered

读取完整的一行getline

NAME
       getline, getdelim - delimited string input
SYNOPSIS
       #include <stdio.h>
       ssize_t getline(char **lineptr, size_t *n, FILE *stream); //reads  an  entire  line  from  stream, 包括'\n' 但不包括'\0'
       ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);

getline实例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv){
        FILE *fp;
        char *linebuf;
        size_t linesize;
        if(argc<2){
                fprintf(stderr,"Usage:...");
                exit(1);
        }
        fp=fopen(argv[1],"r");
        if(fp ==NULL){
                perror("open error");
                exit(1);
        }
        //!!!!非常重要!!!!
        linebuf =NULL; //不释放可能会造成内存泄漏
        linesize =0;
        while(1){
                if (getline(&linebuf,&linesize,fp)<0)
                        break;
                printf("%ld\n",strlen(linebuf));
                printf("%ld\n",linesize);
        }
        fclose(fp);
        //free(linebuf); 不推荐使用free释放内存
        exit(0);
}

临时文件

  1. 如何不冲突
  2. 及时销毁
  3. 函数tmpnam、tmpfile

man tmpnam

#include <stdio.h>
char *tmpnam(char *s);

man tmpfile

#include <stdio.h>
FILE *tmpfile(void); //create a temporary file 创建临时文件(匿名文件)

系统调用IO/文件IO

文件描述符(fd)是贯穿文件IO始终的类型。
什么是文件描述符?
文件描述符的本质是整数,索引下标,优先使用可用的最小值。

怎么使用文件描述符?
文件IO操作:open、close、read、write、lseek

文件IO VS 标准IO

IO的效率问题

文件共享

原子操作

程序中的重定向: fup、dup2

同步:sync,fsync,fdatasync

fcntl()
ioctl()
/dev/fd/
在这里插入图片描述

open

       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>
       //C语言没有重载,这里是通过变参函数来实现的
       //可通过多传参数,编译,查看是否
       int open(const char *pathname, int flags);
       int open(const char *pathname, int flags, mode_t mode);
       		flags,
       			必选项:O_RDONLY  O_WRONLY  O_RDWR
       				
       			可选项:

cache 读加速
buffer 写加速

close

man  close
       #include <unistd.h>
       int close(int fd);   //close a file descriptor

read

       #include <unistd.h>
       ssize_t read(int fd, void *buf, size_t count); //       read - read from a file descriptor

write

       #include <unistd.h>
       ssize_t write(int fd, const void *buf, size_t count); //       write - write to a file descriptor

lseek

       #include <sys/types.h>
       #include <unistd.h>
       off_t lseek(int fd, off_t offset, int whence); //lseek - reposition read/write file offset
       		whence取值:
       			SEEK_SET	SEEK_CUR		SEEK_END

文件IO VS 标准IO

标准IO
FILE
stdin、stdout、stderr
系统IO
int
fd:0,1,2
有没有打开0、1、2取决于父进程,因为是继承来的
示例: 传达室邮递员送取信件
区别:响应速度&吞吐量
面试题:如何使一个程序变快?
注意:标准IO与文件IO不可以混用
转换:fileno,fdopen

示例:

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
int main(){
    putchar('a');
    write(1,"b",1);
    putchar('a');
    write(1,"b",1);
    putchar('a');
    write(1,"b",1);
    exit(0);
}//输出结果应为bbbaaa
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值