C语言:高级IO

非阻塞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 

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值