非阻塞IO和阻塞IO
man手册7章是在将机制。
------- EINTR:(error interrupt)是阻塞的系统调用,动作非常的慢,这个过程被信号打断了,但并不是操作失败,故是个假错。
----------EAGAIN.(error again) 是非堵塞的调用,表示,尝试去做了,但是现在没有数据,并不是真的出错了(并不是当前系统调用函数的问题)。
有限状态机编程
简单流程:一个程序的自然流程是结构化的就叫简单流程。
复杂流程:一个程序的自然流程是非结构化的就叫简单流程。
relay.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define TTY1 "/dev/tty11"
#define TTY2 "/dev/tty12"
#define BUFSIZE 1024
enum
{
STATE_R = 1, //读态
STATE_W = 2, // 写态
STATE_Ex, // 异常态
STATE_T //结束态
};
struct fsm_st
{
int state;
int sfd;
int dfd;
char buf[BUFSIZE];
int len;
int pos;
char *errstr;
};
void fsm_driver(struct fsm_st*fsm)
{
int ret;
switch(fsm->state)
{
case STATE_R:
fsm->len = read(fsm->sfd,fsm->buf,BUFSIZE);
if(fsm->len ==0)
fsm->state = STATE_T;
else if(fsm->len < 0)
{
if(errno == EAGAIN) //假错
fsm->state = STATE_R;
else
{
fsm->errstr = "read()";
fsm->state = STATE_Ex;
}
}
else
{
fsm->pos = 0;
fsm->state = STATE_W;
}
break;
case STATE_W:
ret = write(fsm->dfd,fsm->buf+fsm->pos,fsm->len);
if(ret<0)
{
if(errno == EAGAIN)
fsm->state = STATE_W;
else
{
fsm->errstr = "write()";
fsm->state = STATE_Ex;
}
}
else
{
fsm->len -= ret;
fsm->pos += ret;
if(fsm->len ==0)
fsm->state = STATE_R;
else
fsm->state = STATE_W;
}
break;
case STATE_Ex:
perror(fsm->errstr);
fsm->state = STATE_T;
break;
case STATE_T:
/*do sth*/
break;
default:
abort();//出错人为退出。
break;
}
}
void relay(int fd1,int fd2)
{
int fd1_save,fd2_save;
struct fsm_st fsm12,fsm21;
fd1_save = fcntl(fd1,F_GETFL);
fcntl(fd1,F_SETFL,fd1_save| O_NONBLOCK);
fd2_save = fcntl(fd2,F_GETFL);
fcntl(fd2,F_SETFL,fd2_save| O_NONBLOCK);
fsm12.state =STATE_R;
fsm12.sfd = fd1;
fsm12.dfd = fd2;
fsm21.state =STATE_R;
fsm21.sfd = fd2;
fsm21.dfd = fd1;
while( fsm12.state != STATE_T || fsm21.state != STATE_T)
{
//推状态机
fsm_driver(&fsm12);
fsm_driver(&fsm21);
}
//状态还原
fcntl(fd1,F_SETFL,fd1_save);
fcntl(fd2,F_SETFL,fd2_save);
}
int main()
{
int fd1,fd2;
fd1 = open(TTY1,O_RDWR);
if(fd1< 0)
{
perror("open()");
exit(1);
}
write(fd1,"TTY1\n",5);
fd2 = open(TTY2,O_RDWR|O_NONBLOCK); //以非堵塞形式打开
write(fd2,"TTY2\n",5);
relay(fd1,fd2);
close(fd1);
close(fd2);
return 0;
}
在虚拟机中使用Ctrl+Alt+ F11 切换11终端设备。12同理。
可以使用dia工具进行绘图,类似于windows下的Visio。
非阻塞IO
man.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "relayer.h"
#define TTY1 "/dev/tty11"
#define TTY2 "/dev/tty12"
#define TTY3 "/dev/tty10"
#define TTY4 "/dev/tty9"
#define BUFSIZE 1024
int main()
{
int fd1,fd2;
int job1;
fd1 = open(TTY1,O_RDWR);
if(fd1< 0)
{
perror("open()");
exit(1);
}
write(fd1,"TTY1\n",5);
fd2 = open(TTY2,O_RDWR|O_NONBLOCK); //以非堵塞形式打开
write(fd2,"TTY2\n",5);
job1 = rel_addjob(fd1,fd2);
if(job1<0)
{
fprintf(stderr,"rel_addjob():%s\n",strerror(-job1));
exit(1);
}
int fd3,fd4;
int job2;
fd3 = open(TTY3,O_RDWR);
write(fd3,"TTY3\n",5);
fd4 = open(TTY3,O_RDWR);
write(fd4,"TTY4\n",5);
job2 =rel_addjob(fd3,fd4);
while(1);
close(fd1);
close(fd2);
close(fd3);
close(fd4);
return 0;
}
relayer.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include "relayer.h"
#define TTY1 "/dev/tty11"
#define TTY2 "/dev/tty12"
#define BUFSIZE 1024
static struct rel_job_st* rel_job[REL_JOBMAX];
static pthread_mutex_t mut_rel_job = PTHREAD_MUTEX_INITIALIZER;
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
enum
{
STATE_R = 1, //读态
STATE_W = 2, // 写态
STATE_Ex, // 异常态
STATE_T //结束态
};
struct rel_fsm_st
{
int state;
int sfd;
int dfd;
char buf[BUFSIZE];
int len;
int pos;
char *errstr;
int64_t count;
};
struct rel_job_st
{
int job_state;
int fd1;
int fd2;
struct rel_fsm_st fsm12,fsm21;
int fd1_save,fd2_save;
// struct timerval start,end;
};
void fsm_driver(struct rel_fsm_st*fsm)
{
int ret;
switch(fsm->state)
{
case STATE_R:
fsm->len = read(fsm->sfd,fsm->buf,BUFSIZE);
if(fsm->len ==0)
fsm->state = STATE_T;
else if(fsm->len < 0)
{
if(errno == EAGAIN) //假错
fsm->state = STATE_R;
else
{
fsm->errstr = "read()";
fsm->state = STATE_Ex;
}
}
else
{
fsm->pos = 0;
fsm->state = STATE_W;
}
break;
case STATE_W:
ret = write(fsm->dfd,fsm->buf+fsm->pos,fsm->len);
if(ret<0)
{
if(errno == EAGAIN)
fsm->state = STATE_W;
else
{
fsm->errstr = "write()";
fsm->state = STATE_Ex;
}
}
else
{
fsm->len -= ret;
fsm->pos += ret;
if(fsm->len ==0)
fsm->state = STATE_R;
else
fsm->state = STATE_W;
}
break;
case STATE_Ex:
perror(fsm->errstr);
fsm->state = STATE_T;
break;
case STATE_T:
/*do sth*/
break;
default:
abort();//出错人为退出。
break;
}
}
void* thr_relayer(void*p)
{
while(1)
{
pthread_mutex_lock(&mut_rel_job);
for(int i=0;i<REL_JOBMAX;i++)
{
if(rel_job[i] !=NULL)
{
if(rel_job[i]->job_state == STATE_RUNNING)
{
fsm_driver(&rel_job[i]->fsm12);
fsm_driver(&rel_job[i]->fsm21);
if(rel_job[i]->fsm12.state == STATE_T && rel_job[i]->fsm21.state ==STATE_T)
{
rel_job[i]->job_state = STATE_OVER;
}
}
}
}
pthread_mutex_unlock(&mut_rel_job);
}
return NULL;
}
//moudle_unload
void moudle_load(void)
{
pthread_t tid_relayer;
int err;
err = pthread_create(&tid_relayer,NULL,thr_relayer,NULL);
}
int get_free_pos_unlocked()
{
for(int i=0;i< REL_JOBMAX;i++)
{
if(rel_job[i]==NULL)
return i;
}
return -1;
}
int rel_addjob(int fd1,int fd2)
{
struct rel_job_st*me;
pthread_once(&init_once,moudle_load);
me = malloc(sizeof(*me));
if(me == NULL)
return -ENOMEM;
me->fd1 = fd1;
me->fd2 = fd2;
me->job_state = STATE_RUNNING;
me->fd1_save = fcntl(me->fd1,F_GETFL);
fcntl(me->fd1,F_SETFL,me->fd1_save| O_NONBLOCK);
me->fd2_save = fcntl(me->fd2,F_GETFL);
fcntl(me->fd2,F_SETFL,me->fd2_save| O_NONBLOCK);
me->fsm12.sfd = me->fd1;
me->fsm12.dfd = me->fd2;
me->fsm12.state = STATE_R;
me->fsm21.sfd = me->fd2;
me->fsm21.dfd = me->fd1;
me->fsm21.state = STATE_R;
int pos;
pthread_mutex_lock(&mut_rel_job);
pos = get_free_pos_unlocked();
if(pos <0)
{
pthread_mutex_unlock(&mut_rel_job);
fcntl(me->fd1,F_SETFL,me->fd1_save);
fcntl(me->fd2,F_SETFL,me->fd2_save);
free(me);
return -ENOSPC;
}
rel_job[pos] = me;
pthread_mutex_unlock(&mut_rel_job);
return pos;
}
relayer.h
#ifndef RELAYER_H
#define RELAYER_H
#define REL_JOBMAX 10000
enum
{
STATE_RUNNING= 1,
STATE_CANCELED,
STATE_OVER
};
struct rel_stat_st
{
int status;
int fd1;
int fd2;
int64_t count12,count21;
// struct timeval start,end;
};
int rel_addjob(int fd1,int fd2);
/*
return >=0 成功,返回当前任务的ID
== -EINVAL 失败,参数非法
== -ENOSPC 失败,任务数组满
== -ENOMEM 失败,内存分配有误
*/
#if 0
int rel_canceljob(int id);
/*
return == 0 成功,指定任务取消成功
== -EINVAL 失败,参数非法
== -EBUSY 失败,任务已经被取消
*/
int rel_waitjob(int id,struct rel_stat_st*);
/*
return == 0 成功,指定任务已经终止并返回状态
== -EINVAL 失败,参数非法
*/
int rel_statjob(int id,struct rel_stat_st*);
/*
return == 0 成功,指定任务状态已经返回
== -EINVAL 失败,参数非法
*/
#endif
#endif
makefile
CFLAGS += -pthread
LDFLAGS += -pthread
all:relayer
relayer:relayer.o main.o
gcc $^ -o $@ $(CFLAGS)
clean:
rm -rf *.o relayer
IO多路转接
监视文件描述符行为,要是有了改变就做后续操作。select poll epoll
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout); //古老,移植性好,数组实现。以事件为单位。
int poll(struct pollfd *fds, nfds_t nfds, int timeout); // 链表实现。以文件为单位组织事件。
epoll() //linux下的方言,epoll可以简化用户使用,不可以移植,底层是红黑树。
select
可以实现安全的休眠。
void FD_CLR(int fd, fd_set *set); 从集合中删除
int FD_ISSET(int fd, fd_set *set);判断fd是否存在在set
void FD_SET(int fd, fd_set *set); 将fd加入set中。
void FD_ZERO(fd_set *set); 清空文件描述符
第一 参数ndfs是目前最大文件描述符+1,第二参数:读集合 第三参数:写集合
第四参数:异常集合 第五个参数:超时设置。返回值:成功返回文件描述符个数。失败返回-1设置error.超时返回EINTR假错。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#define TTY1 "/dev/tty11"
#define TTY2 "/dev/tty12"
#define BUFSIZE 1024
enum
{
STATE_R = 1, //读态
STATE_W = 2, // 写态
STATE_AUTO,
STATE_Ex, // 异常态
STATE_T //结束态
};
struct fsm_st
{
int state;
int sfd;
int dfd;
char buf[BUFSIZE];
int len;
int pos;
char *errstr;
};
void fsm_driver(struct fsm_st*fsm)
{
int ret;
switch(fsm->state)
{
case STATE_R:
fsm->len = read(fsm->sfd,fsm->buf,BUFSIZE);
if(fsm->len ==0)
fsm->state = STATE_T;
else if(fsm->len < 0)
{
if(errno == EAGAIN) //假错
fsm->state = STATE_R;
else
{
fsm->errstr = "read()";
fsm->state = STATE_Ex;
}
}
else
{
fsm->pos = 0;
fsm->state = STATE_W;
}
break;
case STATE_W:
ret = write(fsm->dfd,fsm->buf+fsm->pos,fsm->len);
if(ret<0)
{
if(errno == EAGAIN)
fsm->state = STATE_W;
else
{
fsm->errstr = "write()";
fsm->state = STATE_Ex;
}
}
else
{
fsm->len -= ret;
fsm->pos += ret;
if(fsm->len ==0)
fsm->state = STATE_R;
else
fsm->state = STATE_W;
}
break;
case STATE_Ex:
perror(fsm->errstr);
fsm->state = STATE_T;
break;
case STATE_T:
/*do sth*/
break;
default:
abort();//出错人为退出。
break;
}
}
int max(int fd1,int fd2)
{
if(fd1>fd2)
return fd1;
return fd2;
}
void relay(int fd1,int fd2)
{
int fd1_save,fd2_save;
struct fsm_st fsm12,fsm21;
fd1_save = fcntl(fd1,F_GETFL);
fcntl(fd1,F_SETFL,fd1_save| O_NONBLOCK);
fd2_save = fcntl(fd2,F_GETFL);
fcntl(fd2,F_SETFL,fd2_save| O_NONBLOCK);
fsm12.state =STATE_R;
fsm12.sfd = fd1;
fsm12.dfd = fd2;
fsm21.state =STATE_R;
fsm21.sfd = fd2;
fsm21.dfd = fd1;
while( fsm12.state != STATE_T || fsm21.state != STATE_T)
{
//布置监视任务,
fd_set rset,wset;
FD_ZERO(&rset);
FD_ZERO(&wset);
if(fsm12.state == STATE_R)
FD_SET(fsm12.sfd,&rset);
if(fsm12.state == STATE_W)
FD_SET(fsm12.dfd,&wset);
if(fsm21.state == STATE_R)
FD_SET(fsm21.sfd,&rset);
if(fsm21.state == STATE_W)
FD_SET(fsm21.dfd,&wset);
//监视
if(fsm12.state <STATE_AUTO || fsm21.state <STATE_AUTO )
{
int num;
num = select(max(fd1,fd2)+1,&rset,&wset,NULL,NULL); //忙等
if(num<0)
{
if(num == EINTR)
continue;
perror("select()");
exit(1);
}
}
//查看监视结果
//根据结果推状态机
if(FD_ISSET(fd1,&rset) || FD_ISSET(fd2,&wset) || fsm12.state >STATE_AUTO)
fsm_driver(&fsm12);
if(FD_ISSET(fd2,&rset) || FD_ISSET(fd1,&wset) || fsm21.state >STATE_AUTO)
fsm_driver(&fsm21);
}
//状态还原
fcntl(fd1,F_SETFL,fd1_save);
fcntl(fd2,F_SETFL,fd2_save);
}
int main()
{
int fd1,fd2;
fd1 = open(TTY1,O_RDWR);
if(fd1< 0)
{
perror("open()");
exit(1);
}
write(fd1,"TTY1\n",5);
fd2 = open(TTY2,O_RDWR|O_NONBLOCK); //以非堵塞形式打开
write(fd2,"TTY2\n",5);
relay(fd1,fd2);
close(fd1);
close(fd2);
return 0;
}
缺点:
1.古老,每次出错都会清空原来内容。
2. 监听文件描述符个数要是超出最大值会溢出。
优点:
1.移植性好。
2.方便上手。
poll
以文件描述符为单位组织事件。
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
第一个参数:结构体数组的起始地址。第二个参数:数组的总数量。第三个参数:超时设置(0非堵塞,-1堵塞,其他超时时间)。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#define TTY1 "/dev/tty11"
#define TTY2 "/dev/tty12"
#define BUFSIZE 1024
enum
{
STATE_R = 1, //读态
STATE_W = 2, // 写态
STATE_AUTO,
STATE_Ex, // 异常态
STATE_T //结束态
};
struct fsm_st
{
int state;
int sfd;
int dfd;
char buf[BUFSIZE];
int len;
int pos;
char *errstr;
};
void fsm_driver(struct fsm_st*fsm)
{
int ret;
switch(fsm->state)
{
case STATE_R:
fsm->len = read(fsm->sfd,fsm->buf,BUFSIZE);
if(fsm->len ==0)
fsm->state = STATE_T;
else if(fsm->len < 0)
{
if(errno == EAGAIN) //假错
fsm->state = STATE_R;
else
{
fsm->errstr = "read()";
fsm->state = STATE_Ex;
}
}
else
{
fsm->pos = 0;
fsm->state = STATE_W;
}
break;
case STATE_W:
ret = write(fsm->dfd,fsm->buf+fsm->pos,fsm->len);
if(ret<0)
{
if(errno == EAGAIN)
fsm->state = STATE_W;
else
{
fsm->errstr = "write()";
fsm->state = STATE_Ex;
}
}
else
{
fsm->len -= ret;
fsm->pos += ret;
if(fsm->len ==0)
fsm->state = STATE_R;
else
fsm->state = STATE_W;
}
break;
case STATE_Ex:
perror(fsm->errstr);
fsm->state = STATE_T;
break;
case STATE_T:
/*do sth*/
break;
default:
abort();//出错人为退出。
break;
}
}
int max(int fd1,int fd2)
{
if(fd1>fd2)
return fd1;
return fd2;
}
void relay(int fd1,int fd2)
{
int fd1_save,fd2_save;
struct fsm_st fsm12,fsm21;
fd1_save = fcntl(fd1,F_GETFL);
fcntl(fd1,F_SETFL,fd1_save| O_NONBLOCK);
fd2_save = fcntl(fd2,F_GETFL);
fcntl(fd2,F_SETFL,fd2_save| O_NONBLOCK);
fsm12.state =STATE_R;
fsm12.sfd = fd1;
fsm12.dfd = fd2;
fsm21.state =STATE_R;
fsm21.sfd = fd2;
fsm21.dfd = fd1;
struct pollfd pfd[2];
pfd[0].fd = fd1;
pfd[1].fd = fd2;
while( fsm12.state != STATE_T || fsm21.state != STATE_T)
{
//布置监视任务,
pfd[0].events = 0;
pfd[1].events = 0;
if(fsm12.state == STATE_R)
pfd[0].events |= POLLIN;
if(fsm21.state == STATE_W)
pfd[0].events |= POLLOUT;
if(fsm12.state == STATE_R)
pfd[1].events |= POLLOUT;
if(fsm21.state == STATE_W)
pfd[1].events |= POLLIN;
//监视
if(fsm12.state <STATE_AUTO || fsm21.state <STATE_AUTO )
{
int num;
num = poll(pfd,2,-1);
while(num<0)
{
if(num == EINTR)
continue;
perror("select()");
exit(1);
}
}
//查看监视结果
//根据结果推状态机
if(pfd[0].revents & POLLIN || pfd[1].revents & POLLOUT || fsm12.state >STATE_AUTO)
fsm_driver(&fsm12);
if(pfd[0].revents & POLLOUT || pfd[1].revents & POLLIN || fsm12.state >STATE_AUTO)
fsm_driver(&fsm21);
}
//状态还原
fcntl(fd1,F_SETFL,fd1_save);
fcntl(fd2,F_SETFL,fd2_save);
}
int main()
{
int fd1,fd2;
fd1 = open(TTY1,O_RDWR);
if(fd1< 0)
{
perror("open()");
exit(1);
}
write(fd1,"TTY1\n",5);
fd2 = open(TTY2,O_RDWR|O_NONBLOCK); //以非堵塞形式打开
write(fd2,"TTY2\n",5);
relay(fd1,fd2);
close(fd1);
close(fd2);
return 0;
}
epoll
不方便移植。epoll相当于系统给你管理。
int epoll_create(int size);//返回文件描述符
int epoll_create1(int flags);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events,
int maxevents, int timeout,
const sigset_t *sigmask);
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/epoll.h>
#define TTY1 "/dev/tty11"
#define TTY2 "/dev/tty12"
#define BUFSIZE 1024
enum
{
STATE_R = 1, //读态
STATE_W = 2, // 写态
STATE_AUTO,
STATE_Ex, // 异常态
STATE_T //结束态
};
struct fsm_st
{
int state;
int sfd;
int dfd;
char buf[BUFSIZE];
int len;
int pos;
char *errstr;
};
void fsm_driver(struct fsm_st*fsm)
{
int ret;
switch(fsm->state)
{
case STATE_R:
fsm->len = read(fsm->sfd,fsm->buf,BUFSIZE);
if(fsm->len ==0)
fsm->state = STATE_T;
else if(fsm->len < 0)
{
if(errno == EAGAIN) //假错
fsm->state = STATE_R;
else
{
fsm->errstr = "read()";
fsm->state = STATE_Ex;
}
}
else
{
fsm->pos = 0;
fsm->state = STATE_W;
}
break;
case STATE_W:
ret = write(fsm->dfd,fsm->buf+fsm->pos,fsm->len);
if(ret<0)
{
if(errno == EAGAIN)
fsm->state = STATE_W;
else
{
fsm->errstr = "write()";
fsm->state = STATE_Ex;
}
}
else
{
fsm->len -= ret;
fsm->pos += ret;
if(fsm->len ==0)
fsm->state = STATE_R;
else
fsm->state = STATE_W;
}
break;
case STATE_Ex:
perror(fsm->errstr);
fsm->state = STATE_T;
break;
case STATE_T:
/*do sth*/
break;
default:
abort();//出错人为退出。
break;
}
}
int max(int fd1,int fd2)
{
if(fd1>fd2)
return fd1;
return fd2;
}
void relay(int fd1,int fd2)
{
int fd1_save,fd2_save;
struct fsm_st fsm12,fsm21;
fd1_save = fcntl(fd1,F_GETFL);
fcntl(fd1,F_SETFL,fd1_save| O_NONBLOCK);
fd2_save = fcntl(fd2,F_GETFL);
fcntl(fd2,F_SETFL,fd2_save| O_NONBLOCK);
fsm12.state =STATE_R;
fsm12.sfd = fd1;
fsm12.dfd = fd2;
fsm21.state =STATE_R;
fsm21.sfd = fd2;
fsm21.dfd = fd1;
int epfd;
epfd = epoll_create(10);
if(epfd <0)
{
perror("epoll_create()");
exit(1);
}
struct epoll_event ev;
ev.events = 0;
ev.data.fd = fd1;
epoll_ctl(epfd,EPOLL_CTL_ADD,fd1,&ev);
ev.events = 0;
ev.data.fd = fd2;
epoll_ctl(epfd,EPOLL_CTL_ADD,fd2,&ev);
while( fsm12.state != STATE_T || fsm21.state != STATE_T)
{
//布置监视任务,
ev.data.fd = fd1;
ev.events = 0;
if(fsm12.state == STATE_R)
ev.events|= EPOLLIN;
if(fsm21.state == STATE_W)
ev.events|= EPOLLOUT;
epoll_ctl(epfd,EPOLL_CTL_MOD,fd1,&ev);
ev.data.fd = fd2;
ev.events = 0;
if(fsm12.state == STATE_R)
ev.events |= EPOLLOUT;
if(fsm21.state == STATE_W)
ev.events |= EPOLLIN;
//监视
if(fsm12.state <STATE_AUTO || fsm21.state <STATE_AUTO )
{
int num;
num = epoll_wait(epfd,&ev,1,-1);
while(num<0)
{
if(num == EINTR)
continue;
perror("epoll_wait()");
exit(1);
}
}
//查看监视结果
//根据结果推状态机
if( (ev.data.fd == fd1 && (ev.events & EPOLLIN) ) || \
(ev.data.fd == fd2 && (ev.events & EPOLLOUT ))|| \
fsm12.state >STATE_AUTO)
fsm_driver(&fsm12);
if( (ev.data.fd == fd2 && (ev.events & EPOLLIN) ) || \
(ev.data.fd == fd1 && (ev.events & EPOLLOUT ))|| \
fsm12.state >STATE_AUTO)
fsm_driver(&fsm21);
}
//状态还原
fcntl(fd1,F_SETFL,fd1_save);
fcntl(fd2,F_SETFL,fd2_save);
close(epfd);
}
int main()
{
int fd1,fd2;
fd1 = open(TTY1,O_RDWR);
if(fd1< 0)
{
perror("open()");
exit(1);
}
write(fd1,"TTY1\n",5);
fd2 = open(TTY2,O_RDWR|O_NONBLOCK); //以非堵塞形式打开
write(fd2,"TTY2\n",5);
relay(fd1,fd2);
close(fd1);
close(fd2);
return 0;
}
其他读写函数
#include <sys/uio.h>
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
struct iovec {
void *iov_base; /* Starting address */
size_t iov_len; /* Number of bytes to transfer */
};
操作对象不是完整的空间,将多个碎片空间写到同一个文件中。
readn()
writen()
Linux环境高级编程书中,自己实现的内容,unix标准没有。
存储映射IO
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
int munmap(void *addr, size_t length);
mmap.c
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char*argv[])
{
if(argc<2)
{
printf("Usage...\n");
exit(1);
}
int fd = open(argv[1],O_RDONLY);
struct stat statres;
if(fstat(fd,&statres)< 0)
{
perror("fstat()");
exit(1);
}
char*str;
str = mmap(NULL,statres.st_size,PROT_READ,MAP_SHARED,fd,0); //内存映射
if(str == MAP_FAILED)
{
perror("mmap");
exit(1);
}
close(fd);
int count = 0;
for(int i=0;i<statres.st_size;i++)
{
if(str[i]=='a')
count++;
}
printf("count = %d\n",count);
munmap(str,statres.st_size);
return 0;
}
shm.c
mmap实现父子进程通信 (共享内存)
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char*argv[])
{
if(argc<2)
{
printf("Usage...\n");
exit(1);
}
int fd = open(argv[1],O_RDONLY);
struct stat statres;
if(fstat(fd,&statres)< 0)
{
perror("fstat()");
exit(1);
}
char*str;
str = mmap(NULL,statres.st_size,PROT_READ,MAP_SHARED,fd,0); //内存映射
if(str == MAP_FAILED)
{
perror("mmap");
exit(1);
}
close(fd);
int count = 0;
for(int i=0;i<statres.st_size;i++)
{
if(str[i]=='a')
count++;
}
printf("count = %d\n",count);
munmap(str,statres.st_size);
return 0;
}
文件锁
fcntl
lockf
flock
设置空洞文件进行多线程下载时,可以用文件锁来锁文件。(两个文件同时打开,关闭会导致文件意外解锁的情况)
add.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/wait.h>
#define FILENAME "/tmp/out"
#define PROCNUM (20)
void func_add(void);
int main()
{
pid_t pid;
int i,j,mark;
int err;
for(i =0;i<PROCNUM;i++)
{
pid = fork();
if(pid ==0)
{
func_add();
exit(0);
}
if(pid >0)
{
}
}
for(i=0;i<PROCNUM;i++)
{
wait(NULL);
}
return 0;
}
void func_add()
{
FILE*fp;
char line_buf[1024];
int len_size = 1024;
puts("Begin");
fp = fopen(FILENAME,"r+");
int fd = fileno(fp);
lockf(fd,F_LOCK,0);//全部锁文件
fgets(line_buf,len_size,fp);
fseek(fp,0,SEEK_SET);
sleep(1);
fprintf(fp,"%d \n",atoi(line_buf)+1);
fflush(fp);
lockf(fd,F_ULOCK,0);
fclose(fp);
puts("End");
}
管道简单实现
mypipe.c
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include "mypipe.h"
struct mypipe_st
{
int head;
int tail;
char data[PIPESIZE];
int datasize;
int count_rd;
int count_wr;
pthread_mutex_t mut;
pthead_cond_t cond;
};
mypipe_t* mypipe_init(void )
{
struct mypipe_st*me;
me = malloc(sizeof(*me));
if(me ==NULL)
{
return me;
}
me->head = 0;
me->tail = 0;
me->datasize = 0;
me->count_rd = 0;
me->cound_wr = 0;
pthread_mutex_init(&me->mut,NULL);
pthread_cond_init(&me->cond,NULL);
return me;
}
int mypipe_register(mypipe_t*ptr,int opmap)
{
/*if err*/
struct mypipe_st *me = ptr;
pthread_mutex_lock(&me->mut);
if(opmap & MYPIPE_READ)
{
me->count_rd++;
}
if(opmap & MYPIPE_WRITE)
{
me->count_wr++;
}
pthread_cond_broadcast(&me->cond);//叫醒其他等待的线程。
while(me->count_rd <=0 || me->count_wr <= 0)
{
pthread_cond_wait(&me->cond,&me->mut);
}
pthread_mutex_unlock(&me->mut);
return 0;
}
int mypipe_unregister(mypipe_t*ptr,int opmap)
{
struct mypipe_st*me = ptr;
pthread_mutex_lock(&me->mut);
if(opmap & MYPIPE_READ)
{
me->count_rd--;
}
if(opmap & MYPIPE_WRITE)
{
me->count_wr--;
}
pthread_cond_broadcast(&me->cond);//叫醒其他等待的线程。
pthread_mutex_unlock(&me->mut);
}
mypipe_readbyte_unlocked(struct mypipe_t*me,char*datap)
{
if(me->datasize<=0)
return -1;
*datap = me->data[me->head];
me->head = next(me->head);
me->datasize --;
return 0;
}
int mypipe_read(mypipe_t*ptr,void*buf,size_t count)
{
struct mypipe_st*me = ptr;
int i;
pthread_mutex_lock(&me->mut);
while(me->datasize<=0 && me->count_wr >0 )
{
pthread_cond_wait(&me->cond,&me->mut);
}
if(me->datasize<=0 && me->count_wr <=0)
{
pthread_mutex_unlock(&me->mut);
return 0; //没有数据,没有写者就退出。
}
for( i=0;i< count;i++)
{
int ret;
ret = mypipe_readbyte_unlocked(me,buf+i);
if(ret != 0)
{
break;
}
}
pthread_cond_broadcast(&me->cond);
pthread_mutex_unlock(&me->mut);
return i;
}
int mypipe_write(mypipe_t*ptr,const void*buf,size_t count)
{
}
int mypipe_destroy(mypipe_t* ptr)
{
struct mypipe_st*me;
me = ptr;
pthread_mutex_destroy(&me->mut);
pthread_cond_destroy(&me->cond);
free(ptr);
return 0;
}
mypipe.h
#ifndef MYPIPE_H
#define MYPIPE_H
#define PIPESIZE 1024
#define MYPIPE_READ 0x00000001UL
#define MYPIPE_WRITE 0x00000002UL
typedef void mypipe_t;
mypipe_t* mypipe_init(void );
int mypipe_register(mypipe_t*,int opmap);
int mypipe_unregister(mypipe_t*,int opmap);
int mypipe_read(mypipe_t*,void*buf,size_t count);
int mypipe_write(mypipe_t*,const void*buf,size_t count);
int mypipe_destroy(mypipe_t* );
#endif