建立三个文件 分别bin include src 还有一个makefile

在这三个文件的目录下

1.make

2.进入bin文件,gcc -client.c -o client

3.在bin文件下mkfifo fifo

4.在bin文件下./main fifo 3(开三个线程)

5.再开启一个终端,在bin下 ./client fifo

在客户端发送字符串,服务器受到会返回这个字符串,可以见执行任务的函数修改,来执行其他任务而不是简单的返回字符串,通过修改src文件下的task.c中的excute_task函数

makefile

SRC_DIR := ./src
INC_DIR := ./include
EXE_DIR := ./bin
CC := gcc
CFLAGS := -g -o
SRC_OBJECTS := $(wildcard $(SRC_DIR)/*.c)
INC_OBJECTS := $(wildcard $(INC_DIR)/*.h)
$(EXE_DIR)/main : $(SRC_OBJECTS) $(INC_OBJECTS)$(CC) $(CFLAGS) $@ $(SRC_OBJECTS) -I$(INC_DIR) -lpthread

include文件中的server.h

/*************************************************************************> File Name: server.h> Author: yang> Mail:826123027@qq.com > Created Time: 2014年08月27日 星期三 10:01:27************************************************************************/#ifndef __SERVER_H__
#define __SERVER_H__
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/select.h>
#include <signal.h>
#include<pthread.h>
#define MSG_LEN 1024
#define TASK_CNT 1024
extern pthread_mutex_t mutex;
extern pthread_cond_t cond_master;
extern pthread_cond_t cond_slave;
typedef struct tag_fds{int s_rfd;int s_wfd;struct tag_fds *s_next;
}FD_PAIR,*pFD_PAIR;//建立一个链表,放输入标识符,输出标识符
typedef struct tag_task{char s_msg[1024];int s_fd;
}TASK,*pTASK;//将任务定义成结构体,存放着写描述符和信息
typedef struct tag_que{TASK s_arr[TASK_CNT + 1];int s_front;int s_tail;
}QUEUE,*pQUEUE;//一个人物队列,线程来处理(添加任务,执行任务)
void fds_link_init(pFD_PAIR* phread);//对描述符链表进行操作
void fds_insert(pFD_PAIR* phead,int fd_r,int fd_w);
int fds_find_wfd(pFD_PAIR phead,int fd_r);
void fds_link_delete(pFD_PAIR* phead,int fd_r);void add_task(pQUEUE pq,pTASK pt);//在set集合中寻找那个client发信息了,然后添加任务
void get_task(pQUEUE pq ,pTASK pt);//建立线程的时候用,直接执行任务
void excute_task(pTASK pt);
#endif

src文件中的 fds_link.c

/*************************************************************************> File Name: fds_link.c> Author: yang> Mail:826123027@qq.com > Created Time: 2014年08月27日 星期三 10:19:10************************************************************************/#include<server.h>
void fds_link_init(pFD_PAIR* phead){*phead=NULL;
}
void fds_insert(pFD_PAIR* phead,int fd_r,int fd_w){//向描述符链表插入pFD_PAIR pCur = (pFD_PAIR)calloc(1,sizeof(FD_PAIR));pCur ->s_rfd = fd_r;pCur ->s_wfd = fd_w;pCur ->s_next = *phead;*phead=pCur;
}
int fds_find_wfd(pFD_PAIR phead,int fd_r){//根据读描述符找到写描述符,因为server的set里放的是读描述符,server先看那个客户端给他发信息了,在找相应的读描述符,给给客户端写回结果while(phead){if(phead->s_rfd==fd_r)break;elsephead=phead->s_next;}if(phead == NULL)return -1;elsereturn phead ->s_wfd;
}
void fds_link_delete(pFD_PAIR *phead,int fd_r){//将该描述符链表中删掉pFD_PAIR pPre,pCur;pPre = NULL;pCur = *phead;while(pCur){if(pCur ->s_rfd ==fd_r)break;else{pPre=pCur;pCur=pCur->s_next;}}if(pPre==NULL){//如果链表只有一个元素的情况pPre ->s_next=pCur ->s_next;free(pCur);pCur=NULL;}
}

src 中 task.c

/*************************************************************************> File Name: task.c> Author: yang> Mail:826123027@qq.com > Created Time: 2014年08月27日 星期三 10:31:16************************************************************************/#include "server.h"
static int que_empty(pQUEUE pq)//队列是否空
{return pq -> s_front == pq -> s_tail ;
}
static int que_full(pQUEUE pq)//队列是否满
{return  (pq -> s_tail + 1)%(TASK_CNT + 1) == pq -> s_front ;
}
static int que_cnt(pQUEUE pq)//队列中元素的数量
{return (pq ->s_tail - pq ->s_front + TASK_CNT + 1)%(TASK_CNT + 1) ;
}
void add_task(pQUEUE pq,pTASK pt){pthread_mutex_lock(&mutex);while(que_full(pq))//如果队列为满pthread_cond_wait(&cond_master,&mutex);//让所有server都等着,因为就server往里添加任务pq ->s_arr[pq->s_tail]=*pt;//队列操作pq ->s_tail =(pq->s_tail+1)%(TASK_CNT + 1);{pthread_cond_broadcast(&cond_slave);//通知所有线程多来抢任务啊}pthread_mutex_unlock(&mutex);sleep(1);
}
void get_task(pQUEUE pq,pTASK pt){//执行任务pthread_mutex_lock(&mutex);while(que_empty(pq))//让任务队列为空,所有线程都等着,因为没有任务啦pthread_cond_wait(&cond_slave,&mutex);*pt=(pq ->s_arr)[pq->s_front];pq->s_front=(pq->s_front+1)%(TASK_CNT+1);{pthread_cond_broadcast(&cond_master);//通知server赶紧添加任务}pthread_mutex_unlock(&mutex);sleep(1);
}
void excute_task(pTASK pt){printf("excute_task:%d,%s\n",pt->s_fd,pt->s_msg);//执行任务啦write(pt->s_fd,pt->s_msg,strlen(pt->s_msg));
}

src文件中 main.c

/*************************************************************************> File Name: main.c> Author: yang> Mail:826123027@qq.com > Created Time: 2014年08月27日 星期三 10:44:35************************************************************************/#include<server.h>
pthread_mutex_t mutex;
pthread_cond_t cond_master;
pthread_cond_t cond_slave;
void* slave_handler(void *arg){pthread_detach(pthread_self());pQUEUE pq=(pQUEUE)arg;//任务队列TASK my_task;while(1){get_task(pq,&my_task);//每个线程都保存应该想哪个管道里发的描述符wfdexcute_task(&my_task);//使用excute单独执行任务,因为这样执行什么任务我们可以自己定义sleep(1);}
}
int main(int argc,char *argv[]){if(argc!=3){//当输入的参数不是3的时候提示printf("wrong!");exit(1);}signal(SIGPIPE,SIG_IGN);//忽略SIGPIPE信号,当客户端关闭,服务器还通过管道给客户端发信号,系统就会发送SIGPIPE信号,把程序挂掉signal(SIGQUIT,SIG_IGN);//忽略ctrl + \ 信号int fd_server;//服务器有一个管道来接受客户上线信息QUEUE my_que;//任务队列,线程在这里面找执行任务pFD_PAIR my_list;//输出描述符,输入描述符链表,server通过输入描述符找到客户端输出描述符,然后发送信息fd_set read_set,ready_set;//定义两个集合,server轮回检查谁发信息struct timeval tm;//轮回时间int select_ret;memset(&my_que,0,sizeof(QUEUE));fds_link_init(&my_list);int slave_cnt = atoi(argv[2]);//线程的个数pthread_t *arr=(pthread_t*)calloc(slave_cnt,sizeof(pthread_t));//用来初始化的线程的描述符数组,动态分配pthread_mutex_init(&mutex,NULL);//初始化锁pthread_cond_init(&cond_master,NULL);//初始化等待函数pthread_cond_init(&cond_slave,NULL);int index=0;while(slave_cnt>0){pthread_create(arr+index,NULL,slave_handler,(void*)&my_que);//建立线程,来执行任务slave_cnt--;index++;}fd_server = open(argv[1],O_RDONLY);//从server的那个管道读 出客户端上线信息if(fd_server == -1){perror("open");exit(-1);}FD_ZERO(&read_set);//集合清零FD_SET(fd_server,&read_set);//将fd_server这个描述符添加到集合中while(1){tm.tv_sec=0;tm.tv_usec=1000;ready_set=read_set;//每次循环重新得到集合,因为ready_set每次都变select_ret=select(1024,&ready_set,NULL,NULL,&tm);//集合中有几个描述符if(select_ret==0){continue;}//判断客户端上线else if(select_ret>0){if(FD_ISSET(fd_server,&ready_set)){//fd_server描述符是否有请求,这个函数如果发现某描述符没法请求,就会将该描述符删掉,所以这里一定要用ready_set这个临时的集合char buf[32];memset(buf,0,32);if(read(fd_server,buf,32)==0){//从fd_server描述符读取客户端上线信息==0说明没有上线continue;}else{printf("a client on!\n");//上线了char pipe_name[32];memset(pipe_name,0,32);buf[strlen(buf)-1]='\0';//客户端发送的是pid,通过这个pid客户端建立两个管道,r.getpid(),w.getpid()sprintf(pipe_name,"r.%s",buf);//client readint wfd,rfd;wfd = open(pipe_name,O_WRONLY);//客户端读,那么server就是写了,得到写描述符wfdmemset(pipe_name,0,32);sprintf(pipe_name,"w.%s",buf);//client writerfd=open(pipe_name,O_RDONLY);//得到读描述符,每个客户端有两个管道fds_insert(&my_list,rfd,wfd);//将这对描述符添加到描述符队列里面FD_SET(rfd,&read_set);//将读描述符添加到集合}}//遍历read_set集合,看那个读描述符给server发信息了,发信息就就开始执行任务pFD_PAIR pCur = my_list;while(pCur){printf("start to find!\n");if(FD_ISSET(pCur->s_rfd,&read_set))//client request判断客户在不在set集合,{char buf[1024];memset(buf,0,sizeof(buf));if(read(pCur->s_rfd,buf,1024)==0)//判断客户有没有请求,==0时候就是不请求了{FD_CLR(pCur->s_rfd,&read_set);//相当于客户ctrl+c了,退出了,所以就把该描述符从集合中删掉,这个集合是read_set备份集合int fd_r=pCur->s_rfd;pCur = pCur->s_next;fds_link_delete(&my_list,fd_r);//吧描述符链表对应的位置也删掉}else{TASK tk;memset(&tk,0,sizeof(tk));tk.s_fd=pCur->s_wfd;strcpy(tk.s_msg,buf);//如果没有退出,就将这个任务添加到任务队列,交给线程执行add_task(&my_que,&tk);pCur = pCur->s_next;}}else{pCur = pCur ->s_next;}}}}pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond_master);pthread_cond_destroy(&cond_slave);return 0;
}

bin 文件中的 client.c

/*************************************************************************> File Name: client.c> Author: yang> Mail:826123027@qq.com > Created Time: 2014年08月27日 星期三 11:27:19************************************************************************/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(int argc,char *argv[]){int fd_server,fd_send,fd_recv;char rname[32],wname[32];fd_server = open(argv[1],O_WRONLY);//这是描述符,之前建立好的管道,通过argv传过来,client想server发送登陆信息memset(rname,0,32);memset(wname,0,32);sprintf(rname,"r.%d",getpid());sprintf(wname,"w.%d",getpid());//这两个管道用来client与server通信的mkfifo(rname,0666);//生成两个管道,一个用来client读,server写mkfifo(wname,0666);//用来client写,server读char msg[1024];sprintf(msg,"%d\n",getpid());write(fd_server,msg,strlen(msg));//发送的登陆信息为进程的pid,方便server那面生成管道名(r.getpid(),w.getpid())来读写管道fd_recv = open(rname,O_RDONLY);//得到两个管道的描述符fd_send = open(wname,O_WRONLY);while(memset(msg,0,1024),fgets(msg,1024,stdin)!=NULL){//想管道(server)写信息write(fd_send,msg,strlen(msg));memset(msg,0,1024);read(fd_recv,msg,1024);//从管道(server)接信息write(1,msg,strlen(msg));//打印到屏幕}close(fd_server);close(fd_send);close(fd_recv);return 0;
}

搭建一个服务器框架,进程间利用管道通信,线程处理数据相关推荐

  1. Linux C 进程间的管道通信

    1.进程间的通信方式 a.管道通信:无名管道.有名管道 b.信号通信:包括信号的发送.接收和处理 c.IPC(Inter-Process Communication):共享内存.消息队列.信号灯 ** ...

  2. Linux-C语言-利用有名管道简单实现两个进程间的全双工通信

    有名管道特点: 1.有名管道是对无名管道的改进,它可以使互不相关的两个进程互相通信,并且在文件系统中可见,可以通过文件名来找到. 2.半双工的通信方式,进程通过文件IO来操作有名管道. 3.有名管道遵 ...

  3. 在自己的电脑上搭建一个服务器

    我们平常学习时经常会写一下javaweb程序,我们为了更能逼近现实,就想着自己的javaweb程序发布后,外网的同学能够访问我们的网站,难道我们去买空间,去买域名嘛,其实也没必要,我们只是学习,测试之 ...

  4. 怎样从0开始搭建一个测试框架_0

    怎样从0开始搭建一个测试框架_0 在开始之前,请让我先声明几点: 这个"从0开始"并不是说你不需要任何基础知识,而是指框架从无到有的过程,要开始搭建还是需要一定基础 请确保你已经掌 ...

  5. 用python搭建一个服务器

    用python搭建一个服务器 新建一个python文件(要跟服务器的update文件同级),用来开启服务,命名为:server.py 写入python代码: import SimpleHTTPServ ...

  6. 【前端】搭建一个VUE框架

    大伙好,最近狠狠焦虑了,因为想搞前端技术岗找暑假实习担心自己能力不够,还是希望如果有同学大学期间就决定毕业找工作的话,一定要抓住机会大学期间狠狠锻炼本领噢,不要虚度光阴 说了点题外话,回到正题,焦虑的 ...

  7. 如何搭建一个Spring框架超详细

    如何搭建一个Spring框架,首先我们要先了解Spring的核心构成部分 1.Spring 的构成 IOC 控制反转 spring 框架最核心的部分 DAO spring 对 访问数据库的支持 MVC ...

  8. 如何快速用node在本地搭建一个服务器

    众所周知,服务器是通过安装特殊的软件(或者运行特殊的代码)来提供网络服务的机器.那么我们的电脑可不可以弄成一个服务器,来供他人访问呢? 答案是可以的,这里我们需要按照一下node.js这个软件.具体按 ...

  9. linux进程管理 实现管道通信,Linux进程管理(二)管道通信 · lww’s Blog

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 实验内容试验阻塞型读写过程中的各种情况 试验阻塞型读写过程中的各种情况 利用Posix信号量机制实现进程间对管道的互斥访 ...

  10. 2.12父子进程通过匿名管道通信

    目录 1.pipe函数 2.查看管道缓冲大小 1.pipe函数 #include <unistd.h> int pipe(int pipefd[2]);功能:创建一个匿名管道,用来进程间通 ...

最新文章

  1. python编码问题无法复现_Python编码问题详解
  2. 邮箱的正则表达式验证总结经验
  3. 记录自定义的代码片段位置
  4. python教育学_使用Python处理教育学领域的数据——以某篇期刊论文为例
  5. 小程序与云服务器api接口,小程序云函数调用http api进行对云数据库的操作
  6. HTML+CSS+JS实现 ❤️鼠标悬停性感美女图片特效❤️
  7. 电脑怎么重置host_电脑又双叒叕卡顿?究竟要“重装”还是“重置”?原来这区别大了...
  8. 如何解决SVN 清理失败
  9. mysql中怎么实现Apriori_关联规则算法Apriori的学习与实现
  10. MySQL存储过程中的循环怎么写
  11. 苹果无人车四个最新专利:手势控制变道、车辆导流、路况感知及车辆控制
  12. 杭州一般纳税人和小规模纳税人的区别
  13. 微信公众号过程中都有哪些技巧,提升公众号活跃度
  14. mysql当前时间相减_mysql 查询当前时间加减时间
  15. 云南昆明寺庙方丈还俗完婚 迎娶26岁女老板(图)
  16. 应用内moniter
  17. 读文献——《Deep Residual Learning for Image Recognition》
  18. 10、STL实用技术专题
  19. 不良光线下的语义分割论文调研
  20. 水安ABC考试多选练习题库

热门文章

  1. sqlserver修改实例名
  2. 一个连衣服都穿不整齐的人,代码也肯定写不整齐。
  3. android禁止锁屏保持常亮
  4. java.net.bindexception: address already in use: jvm_bind:8080
  5. mysql 各种字段取值范围 2009-12-23
  6. 【python】-- Django ModelForm
  7. Linux学习笔记--终端命令
  8. Nginx 安装配置
  9. NYOJ760-See LCS again,有技巧的暴力!
  10. C/S系统实现两数求和(非阻塞+epoll+心跳包检测用户在线状况+滚动日志+配置文件.)...