应用开发
2023-01-07 10:54:45 0 举报
AI智能生成
c语言线程,进程,网络通信总结
作者其他创作
大纲/内容
文件管理
IO文件操作
7种文件类型
<font color="#00bcd4">普通,目录,管道,链接,套接字,块,字符设备文件</font>
打开文件 6种方式<font color="#ffb74d">(r ,r+, w,w+,a,a+)</font>
读写文件 <font color="#ffb74d">fread fwrite</font>
关闭文件<font color="#ffb74d">fclose </font>
操作对象
FILE * fp 文件流指针
<font color="#d32f2f">IO 函数操作,不能操作内核,设备</font>
文件描述符 大于0的正整数
函数
access
<font color="#ffb74d">int access(const char*</font><font color="#d32f2f">pathname</font><font color="#ffb74d">,int </font><font color="#d32f2f">mode</font><font color="#ffb74d">)</font>
① pathname -- 文件名,目录名 -- F_OK(存在与否)
② mode --- F_OK W_OK X_OK R_OK
open
<font color="#ffb74d">int open(const char*</font><font color="#d32f2f">pathname</font><font color="#ffb74d">,int </font><font color="#d32f2f">flags</font><font color="#ffb74d">,int </font><font color="#d32f2f">mode</font><font color="#ffb74d">)</font>
mode
权限 八进制数表示 0644 0755
<font color="#ffb74d">int open(const char*</font><font color="#d32f2f">pathname</font><font color="#ffb74d">,int </font><font color="#d32f2f">flags</font><font color="#ffb74d">)</font>
flags 打开方式
O_RDWR 可读可写
O_RDONLY 只读
O_WRONLY 只写
O_APPEND 追加
O_CREAT 创建
read
<font color="#ffb74d">ssize_t read(int </font><font color="#d32f2f">fd</font><font color="#ffb74d">,char*</font><font color="#d32f2f">buf</font><font color="#ffb74d">,size_t </font><font color="#d32f2f">count</font><font color="#ffb74d">)</font>
① fd -- open的返回值
② buf -- 缓冲区大小
③ count -- 读取的字节数
④ 返回值:读取的个数
write
<font color="#ffb74d">ssize_t write(int </font><font color="#d32f2f">fd</font><font color="#ffb74d">,char*</font><font color="#d32f2f">buf</font><font color="#ffb74d">,size_t </font><font color="#d32f2f">count</font><font color="#ffb74d">)</font>
lseek (<b>重新设置读写的位置</b>)
<font color="#ffb74d">off_t lseek(int </font><font color="#d32f2f">fd</font><font color="#ffb74d">,off_t </font><font color="#d32f2f">offset</font><font color="#ffb74d">,int </font><font color="#d32f2f">whence</font><font color="#ffb74d">)</font>
① offset -- 相对于whence的偏移量(+,-,0)
② whence --- SEEK_SET 开头 SEEK_CUR 当前 SEEK_END 末尾
③ 返回值:当前位置距离开头的偏移量
stat (<b>文件的状态信息</b>)
<font color="#ffb74d">int stat(const char *</font><font color="#d32f2f">path</font><font color="#ffb74d">,struct stat*</font><font color="#d32f2f">buf</font><font color="#ffb74d">)</font>
① path -- 文件名,路径名
② buf -- 存放,结构体内容
③ 返回值 -- 0 -- success -1 -- erro
目录操作
mkdir (创建目录)
<font color="#ffb74d"> int mkdir(const char*</font><font color="#d32f2f">pathname</font><font color="#ffb74d">,mode_t </font><font color="#d32f2f">mode</font><font color="#ffb74d">)</font>
① mode -- 权限
② 返回值: 0 -- success -1-- error
rmdir
<font color="#ffb74d">rmdir(const char*</font><font color="#d32f2f">pathname</font><font color="#ffb74d">)</font>
<font color="#ffb74d">opendir </font>(打开目录)
<font color="#ffb74d">DIR*dir = opendir(const char*</font><font color="#b71c1c">pathname</font><font color="#ffb74d">)</font>
pathname -- 目录流
dir --- 目录流指针(存放目录的信息)
<font color="#ffb74d">readdir</font> (读取目录中的文件信息)
<font color="#ffb74d">struct dirent *sp = readdir(DIR*</font><font color="#b71c1c">dir</font><font color="#ffb74d">)</font>
dir --- 目录流指针
sp --- 指向dir目录的结构体指针
d_name 文件名字
子主题
<font color="#ffb74d">rename</font> (修改名字)
<font color="#ffb74d">rename(const char *</font><font color="#b71c1c">oldname</font><font color="#ffb74d">,const char*</font><font color="#b71c1c">newname</font><font color="#ffb74d">)</font>
<b><font color="#ffb74d">remove</font></b>(删除文件,或者空的目录)
<font color="#ffb74d">int remove(const char*</font><font color="#b71c1c">pathname</font><font color="#ffb74d">)</font>
任务(进程)
头文件
<stdio.h>,<unistd.h>,<stdlib.h>,<sys/types.h>
process(进程,动态的过程)
进程的状态
新建 就绪 运行 阻塞 结束 (三个回路)
<font color="#00ff00">ps aux--- linux中的进程</font>
进程的特性
动态性 --- pid不连续,动态产生,动态消亡
并发性 --- 同时执行 -- 宏观
异步性 --- 不同时执行 -- 微观角度,时间差
独立性 --- 父子进程运行在不同的空间中
结构特性 --- 空间不同,所以具有不同的空间体系(栈,堆,数据,代码)
进程的概念
<b style=""><font color="#1b5e20">1、独立可调度的活动</font></b>
<b><font color="#1b5e20">2、抽象的实体,申请和释放资源</font></b>
<b><font color="#1b5e20">3、并行执行,多进程提供基础</font></b>
<b><font color="#1b5e20">4、进程是程序的一次执行过程,动态的,程序执行和资源管理的最小单元。<br>进程的标识符</font></b><br>
父进程 -- 创建子进行<br>fork() -- 函数<br>
pid_t pid = 0;
pid = fork();
pid = fork();<br> if(pid == -1)<br> {<br> perror("fork");<br> exit(1);<br> }
else if(pid == 0)<br> {<br> //子进程<br> printf("the child process![%d-%d]\n",getpid(),getppid());<br> while(1);<br> }
else<br> {<br> //父进程<br> printf("the parent process![%d-%d]\n",pid,getpid());<br> while(1);<br> }
getpid() --- 返回当前进程的pid
getppid() -- 子进程中返回父进程的编号
进程间通信
头文件
<stdio.h> <sys/ipc.h> <sys/shm.h> <stdlib.h> <sys/types.h>
pipe --- 创建无名管道
int pipe(int pfd[2]);
pfd[2] -- 接收管道的描述符
返回值:0 -- success -1 --- error
mkfifo() --- 创建有名管道
int mkfifo(const char*pathname,mode_t mode);
pathname -- 文件名,路径名
mode -- 权限
返回值:0--- success -1 --- error
创建共享内存
<font color="#0d47a1">查看共享内存:ipcs -m</font>
编程步骤:
1、创建共享内存
2、映射共享内存
<p class="MsoNormal" style="margin-left:0cm;text-indent:0cm;mso-list:l0 level1 lfo1"><span lang="EN-US">3、</span><!--[endif]--><span style="font-family:<br>宋体;mso-ascii-font-family:Calibri;mso-ascii-theme-font:minor-latin;mso-fareast-theme-font:<br>minor-fareast;mso-hansi-font-family:Calibri;mso-hansi-theme-font:minor-latin">使用共享内存</span><span lang="EN-US"><o:p></o:p></span></p>
4、断开共享内存
5、回收共享内存
int shmid = shmget(key_t key,size_t size,int shmflg);
key -->ftok() -- 返回值获得
key_t key = ftok(const char*pathname,int pro_id);
pathname -- 存在
返回值:键值
size --->共享内存大小
shmflg --> IPC_CREAT|权限
返回值:shmid --- >共享内存的标识符
线程
概念
线程
(1) 什么是线程
① 线程是进程的一个实体,轻量级进程
② 程序执行流的最小单元
③ 被系统独立调度和分派基本单元
(2) 线程和进程关系
① 进程和线程的概念
② 如果只有一个进程,那么这个进程既是进程也叫做线程
(3) 线程A --创建--- 线程B (线程B只拥有自己需要一点儿栈段空间,其他的共享资源)
(4) 运行图
线程的创建
头文件
#include <stdio.h><br>#include <pthread.h><br>#include <stdlib.h><br>#include <unistd.h><br>#include <string.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,<br> void *(*start_routine) (void *), void *arg);<br>
1、pthread_t*thread --- 新线程的编号
2、attr -- 线程的属性 NULL(默认属性)
3、void *(*start_routine) (void *) --》start_routine 指向返回值和参数都是void*的函数,---》新的线程
4、void*arg -- 作为新的线程的参数
5、返回值:success -- 0 error --- 错误编码 strerror打印
pthread_self() -- 返回线程的编号
pthread_join(pthread_t pid,void**arg) -- 等待新的线程的退出
pthread_exit(void*arg) -- 线程的结束函数(进程结束exit())
互斥锁:锁的机制,上锁和解锁。
互斥问题 -- 只允许一个线程访问
同步问题 -- 在互斥保护下对于线程的有序访问
共享资源的访问 --- 全局变量(两个进程都可以访问到)
通过加锁和解锁的方式实现线程的通信,解决了线程的互斥的问题
1、申请互斥锁
(1) 静态初始化 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 快速互斥锁
(2) 动态初始化 pthread_mutex_init(&mutex,NULL); NULL -- 默认快速互斥锁
2、上锁
pthread_mutex_lock(&mutex);
3、解锁
pthread_mutex_unlock(&mutex);
4、回收资源
pthread_mutex_destroy(&mutex);
条件变量:条件,变量的改变 -- 线程的执行
在互斥锁的保护下<br>读文件 -- 线程 写文件 -- 线程<br>执行 条件为真阻塞 -- 不执行了-- 释放锁<br>改变条件-阻塞线程发送唤醒信号 接受到对方信号--不阻塞执行<br>执行完成,改变条件让自己继续阻塞<br>
总结:读线程先执行 -- 写的线程在执行(重复上一次过程)
条件变量的操作流程
1、初始化
(1) 静态初始化 -- pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
(2) 动态初始化 -- pthread_cond_init(&cond,NULL);
2、阻塞线程(条件为真)
pthread_cond_wait(&cond,&mutex); 等待被唤醒,阻塞一个线程
3、唤醒一个阻塞的线程
pthread_cond_signal(&cond); -- 唤醒线程执行
4、回收资源
pthread_cond_destroy(&cond) -- 回收条件变量
前提,2个线程必须在互斥锁的保护下进行
网络 (网络应用)
UDP编程
客户端
创建socket通信
int sockfd = socket(AF_INET,<font color="#0000ff">SOCK_DGRAM</font>,0)
AF_INET IPV4的协议族
SOCK_DGRAM(数据报套接字)
protocol:指定应用程序使用的通讯协议,一般取值为0,让系统决定使用协议
成功:返回新建的套接字描述符。失败返回-1,并将错误代码放入erron
设置ip和port
struct sockaddr_in seraddr = {0}
清空:bzero(&seraddr,sizeof(seraddr));
seraddr.sin_family = AF_INET;(协议)
seraddr.sin_port = htons(atoi(端口号));
seraddr.sin_addr.s_addr = inet_addr(IP地址);
socklen_t len = sizeof(seraddr);
发送消息
sendto(sockfd,str,sizeof(str),0,(struct sockaddr*)&seraddr,&len);
str:发送的字符串
seraddr:服务器地址
len:seraddr长度
接收消息
ssize_t rv=recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&seraddr,&len);
rv:接收消息的长度
关闭套接字
close(sockfd);
服务器
创建socket通信
int sockfd=socket(AF_INET,<font color="#0000ff">SOCK_DGRAM</font>,0)
绑定IP和port
struct sockaddr_in seraddr={0};
接收消息
struct sockaddr_in cliaddr;
ssize_t rv=recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&cliaddr,&len);
关闭套接字
close(sockfd);
TCP编程
客户端
创建socket通信
int sockfd=socket(AF_INET,<font color="#b71c1c">SOCK_STREAM</font>,0);
AF_INET ipv4的协议族
流式套接字(SOCK_STREAM)
protocol:指定应用程序使用的通讯协议,一般取值为0,让系统决定使用的协议。
成功:返回新建的套接字描述符;失败:返回-1。并将错误码放入 errno
设置ip和port
struct sockaddr_in seraddr = {0}
清空:bzero(&seraddr,sizeof(seraddr));
seraddr.sin_family = AF_INET;(协议)
seraddr.sin_port = htons(atoi(端口号));
seraddr.sin_addr.s_addr = inet_addr(IP地址);
socklen_t len = sizeof(seraddr);
连接服务器
int flag=connect(sockfd,(struct sockaddr*)&seraddr,len)
返回值:0--success 1--error
发送消息
sd=send(sockfd,buf,sizeof(buf),0);
-1失败
也可以用write发送消息格式同read
接收消息
rd=read(sockfd,buf,sizeof(buf));
-1失败
recv接收消息,格式同send
关闭套接字
服务器
创建socket通信
int sockfd=socket(AF_INET,<font color="#b71c1c">SOCK_STREAM</font>,0);
AF_INET ipv4的协议族
流式套接字(SOCK_STREAM)
protocol:指定应用程序使用的通讯协议,一般取值为0,让系统决定使用的协议。
成功:返回新建的套接字描述符;失败:返回-1。并将错误码放入 errno
设置ip和port
struct sockaddr_in seraddr = {0}
清空:bzero(&seraddr,sizeof(seraddr));
seraddr.sin_family = AF_INET;(协议)
seraddr.sin_port = htons(atoi(端口号));
seraddr.sin_addr.s_addr = inet_addr(IP地址);
socklen_t len = sizeof(seraddr);
监听
flag=listen(sockfd,20);
sockfd:监听客户端连接请求
20:l连接队列中的最大个数,自定
接收请求
struct sockaddr_in cliaddr;
socklen_t len=sizeof(cliaddr);
accfd=accept(sockfd,(struct sockaddr*)&cliaddr,&len)
接收消息
rd=read(accfd,buf,sizeof(buf))
-1失败
发送消息
sd=send(accfd,buf,sizeof(buf),0);
-1失败
关闭套接字
通信协议设计
客户端
创建socket通信
int sockfd=socket(AF_INET,<font color="#b71c1c">SOCK_STREAM</font>,0);
AF_INET ipv4的协议族
<font color="#9c27b0">流式套接字(SOCK_STREAM)</font>
protocol:指定应用程序使用的通讯协议,一般取值为0,让系统决定使用的协议。
成功:返回新建的套接字描述符;失败:返回-1。并将错误码放入 errno
设置ip和port
struct sockaddr_in seraddr = {0}
清空:bzero(&seraddr,sizeof(seraddr));
seraddr.sin_family = AF_INET;(协议)
seraddr.sin_port = htons(atoi(端口号));
seraddr.sin_addr.s_addr = inet_addr(IP地址);
socklen_t len = sizeof(seraddr);
连接服务器
int flag=connect(sockfd,(struct sockaddr*)&seraddr,len)
返回值:0--success 1--error
申请空间
char *comm = (char*)malloc(sizeof(struct head)+sizeof(struct body));
head结构体
int type
int id
body结构体
组报
memcpy(comm,&head,sizeof(head));
head存入
②memcpy(comm+sizeof(HEAD),&body,sizeof(body));
body存入
发送消息
sd = send(sockfd,comm,sizeof(HEAD)+sizeof(BODY),0);
-1失败
接收消息
rd=read(sockfd,buf,sizeof(buf));
-1失败
释放空间
free
关闭套接字
服务端
创建socket通信
int sockfd=socket(AF_INET,<font color="#b71c1c">SOCK_STREAM</font>,0);
AF_INET ipv4的协议族
<font color="#9c27b0">流式套接字(SOCK_STREAM)</font>
protocol:指定应用程序使用的通讯协议,一般取值为0,让系统决定使用的协议。
成功:返回新建的套接字描述符;失败:返回-1。并将错误码放入 errno
设置ip和port
struct sockaddr_in seraddr = {0}
清空:bzero(&seraddr,sizeof(seraddr));
seraddr.sin_family = AF_INET;(协议)
seraddr.sin_port = htons(atoi(端口号));
seraddr.sin_addr.s_addr = inet_addr(IP地址);
socklen_t len = sizeof(seraddr);
监听
flag=listen(sockfd,20);
sockfd:监听客户端连接请求
20:l连接队列中的最大个数,自定
接收请求
struct sockaddr_in cliaddr;
socklen_t len=sizeof(cliaddr);
accfd=accept(sockfd,(struct sockaddr*)&cliaddr,&len)
申请空间
char *comm = (char*)malloc(sizeof(struct head)+sizeof(struct body));
head结构体
int type
int id
body结构体
接收消息
rd = read(accfd,comm,sizeof(HEAD)+sizeof(BODY));
-1失败
解析消息内容
HEAD*head = NULL;head = (HEAD*)comm;
BODY*body = NULL;body = (BODY*)(comm+sizeof(HEAD)
发送消息
sd=send(accfd,buf,sizeof(buf),0);
释放空间
free
关闭套接字
select函数(非阻塞链接)
申请文件描述符集合
fd_set readfd;
分支主清空文件描述符的集合题
FD_ZERO(&readfd);
文件描述符顺次添加到文件描述符的集合中
int fd = 0;FD_SET(fd,&readfd);<br>
fd最大5
设置等待时间
struct timeval tm;<br>int retval = 0;
内核监控(select)readfd中文件描述符的变化
select(maxfd+1(6),&readfd,NULL,NULL,&tm);
返回值
-1:error
0:无输入
阻塞的方式等待tm时长
maxfd最大值
判断FD_ISSET()判断readfd中文件描述符状态是否可读,如果可<br>读--通信,如果对方断开,把文件描述符从文件描述符集合中清<br>除(FD_CLR())
FD_ISSET(fd,&readfd)>0可读,通信
否则循环判断fd变化
优缺点
最大连接个数的限制 1024
效率问题低,主要对于集合操作,线性扫面(所有集合中数据查看)
内存拷贝问题,select机制,把所有的文件描述符的集合方法内核中。
函数少,编码简单,能够实现IO的多路复用。
epoll函数(非阻塞链接)
创建socket通信
int sockfd=socket(AF_INET,<font color="#b71c1c">SOCK_STREAM</font>,0);
AF_INET ipv4的协议族
<font color="#9c27b0">流式套接字(SOCK_STREAM)</font>
protocol:指定应用程序使用的通讯协议,一般取值为0,让系统决定使用的协议。
成功:返回新建的套接字描述符;失败:返回-1。并将错误码放入 errno
设置ip和port
struct sockaddr_in seraddr = {0}
清空:bzero(&seraddr,sizeof(seraddr));
seraddr.sin_family = AF_INET;(协议)
seraddr.sin_port = htons(atoi(端口号));
seraddr.sin_addr.s_addr = inet_addr(IP地址);
socklen_t len = sizeof(seraddr);
监听
flag=listen(sockfd,20);
sockfd:监听客户端连接请求
20:l连接队列中的最大个数,自定
创建epoll节点
int epollfd = epoll_create(EPOLL_FLAG);
EPOLL_CTL_ADD 添加fd到节点上
EPOLL_CTL_MOD 修改fd在节点上
EPOLL_CTL_DEL 从节点删除fd
创建节点的结构体并赋值
struct epoll_event ev;
bzero(&ev,sizeof(ev));
ev.events = EPOLLIN;
添加可读的事件
可读EPOLLIN 可写EPOLLOUT 异常EPOLLERR
ev.data.fd = sockfd;
文件描述符
文件描述符 -- 添加到epoll的节点
int flag = epoll_ctl(epollfd,EPOLL_CTL_ADD,sockfd,&ev);
0:success
-1:error
创建监控事件的结构体数组
struct epoll_event even[EPOLL_FLAG];
EPOLL_FLAG值自定义
epoll内核监控这些节点
maxfd = epoll_wait(epollfd,even,EPOLL_FLAG,-1);
even:存储事件
EPOLL_FLAG:检测个数
时间 0 --- 立即返回 , -1-- 阻塞等待事件到来
返回值
活跃的文件描述符的个数max_fd
-1:error
轮询查看文件描述符变化
int ifd = even[i].data.fd;
if((ifd == sockfd)&&(even[i].events == EPOLLIN))
struct sockaddr_in cliaddr;
socklen_t len=sizeof(cliaddr);
accfd=accept(sockfd,(struct sockaddr*)&cliaddr,&len);
accfd添加到epollfd
bzero(&ev,sizeof(ev));<br>ev.events = EPOLLIN;<br>ev.data.fd = accfd;<br>if(epoll_ctl(epollfd,EPOLL_CTL_ADD,accfd,&ev)==-1)<br>{<br>perror("epoll_ctl");<br>exit(1);<br>}
else
接收请求
struct sockaddr_in cliaddr;
socklen_t len=sizeof(cliaddr);
accfd=accept(sockfd,(struct sockaddr*)&cliaddr,&len)
接收消息
rd=read(accfd,buf,sizeof(buf));
-1失败
0:断开连接
回收资源 ,fd -- epollfd中删除
epoll_ctl(epollfd,EPOLL_CTL_DEL,accfd,NULL);
成功
发送消息<br>sd=send(accfd,buf,sizeof(buf),0);
关闭套接字
相对于select的改进
没有最大并发量的限制,打开文件的个数(6位数)
效率问题:只管活跃的文件描述符
内存拷贝问题:epoll机制,会和内存实现“内存共享”方式,减少拷贝,提高效率
0 条评论
下一页