1,获取Posix IPC的名字
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
#include"unpipc.h"
char*px_ipc_name(constchar*name)
{
char*dir,*dst,*slash;
if((dst=malloc(PATH_MAX))==NULL)returnNULL;//分配失败
if((dir=getenv("PX_IPC_NAME"))==NULL)
{//目录名
#ifdefPOSIX_IPC_PREFIX
dir=POSIX_IPC_PREFIX;
#else
dir="/tmp/";
#endif
}
slash=(dir[strlen(dir)-1]=='/')?"":"/";
snprintf(dst,PATH_MAX,"%S%S%S",dir,slash,name);//全路径名称
returndst;
}
2,Mq_open,lsem_open,shm_open用来创建或打开一个IPC对象,第2个参数oflag指定打开IPC对象的方式。消息队列可以以只读,只写或读写任何一种模式打开,信号灯的打开不指定任何模式,共享内存区不能以只写模式打开
3,System V IPC使用key_t作为其名字,通常是先调用stat函数,再调用ftok函数得到的,函数ftok把一个已经存在的路径和一个整数标识符转换为一个key_t值,叫IPC键(IPC key).
4,内核给每个IPC对象维护一个数据结构
structipc_perm
{
uid_tuid;//owner的用户ID
gid_tgid;//owner的组ID
uid_tcuid;//creater的用户ID
gid_tcgid;//creater的组ID
mode_tmode;//读写模式
ulong_tseq;//序列号
key_tkey;//IPCkey
};
ipc_perm 结构体中的seq成员很有意思,它是作为一个计数器,每当删除一个IPC时,内核就递增这个变量,若溢出则循环回到0.
5,管道是最初的Unix IPC形式,其局限性在于没有名字,而且只能由有亲缘关系的进程使用。FIFO又叫有名管道,任何进程之间都能使用。两者都可以使用通常的read和write访问。
6,
#include"unpipc.h"
voidclient(intreadfd,intwritefd)
{//客户
size_tlen;
ssize_tn;
charbuff[MAXLINE];
fgets(buff,MAXLINE,stdin);//读入路径名
len=strlen(buff);
if(buff[len-1]=='/n')//去掉结尾处的行符
len--;
write(writefd,buff,len);//写入管道
while((n==read(readfd,buff,MAXLINE))>0)//从管道读入数据
write(STDOU_FILENO,buff,n);//输出
}
voidserver(intreadfd,intwritefd)
{//服务器
intfd;
ssize_tn;
charbuff[MAXLINE+1];
if((n==read(readfd,buff,MAXLINE))>0)//从管道读入数据
buff[n]='/0';
if((fd=open(buff,0_RDONLY))<0)
{//给客户端返回出错信息
snprintf(buff+n,sizeof(buff)-n,"can'topen,%s/n",strerror(errno));
n=strlen(buff);
write(writefd,buff,n);
}
else
{
while((n=read(fd,huff,MAXLINE))>0)
{//给客户端返回文件内容
write(writefd,buff,n);
}
close(fd);
}
}
intmain(intargc,char**argv)
{
intpipe1[2],pipe2[2];
pid_tchildpid;
//创建两个管道
pipe(pipe1);
pipe(pipe2);
if((childpid=fork())==0)
{
close(pipe1[1]);//子进程关闭管道1的写入端
close(pipe2[0]);//子进程关闭管道2的读出端
server(pipe1[0],pipe2[1]);
exit(0);
}
close(pipe1[0]);//父进程关闭管道1的读出端
close(pipe2[1]);//父进程关闭管道2的写入端
client(pipe2[0],pipe1[1]);
waitpid(childpid,NULL,0);
return0;
}
上面这个例子也可以使用popen和cat来实现
#include"unpipc.h"
intmain(intargc,char**argv)
{
size_tn;
charbuff[MAXLINE],command[MAXLINE];
FILE*fp;
fgets(buff,MAXLINE,stdin);//读入路径名
n=strlen(buff);
if(buff[n-1]=='/n')n--;
snprintf(command,sizeof(command),"cat%s",buff);//构造命令字
fp=popen(command,"r");//创建管道并启动另一个进程
while(fgets(buff,MAXLINE,fp)!=NULL)
fputs(buff,stdout);
pclose(fp);
return0;
}
7,FIFO是一个单向数据流,有一个路径名与之关联,从而允许没有亲缘关系的进程访问同一个FIFO,也叫有名管道(named pipe),由函数mkfifo创建。
#include"unpipc.h"
#defineFIFO1"tmp/fifo.1"
#defineFIFO2"tmp/fifo.2"
voidserver(intreadfd,intwritefd)
{//服务器
intfd;
ssize_tn;
charbuff[MAXLINE+1];
if((n==read(readfd,buff,MAXLINE))>0)//从管道读入数据
buff[n]='/0';
if((fd=open(buff,0_RDONLY))<0)
{//给客户端返回出错信息
snprintf(buff+n,sizeof(buff)-n,"can'topen,%s/n",strerror(errno));
n=strlen(buff);
write(writefd,buff,n);
}
else
{
while((n=read(fd,huff,MAXLINE))>0)
{//给客户端返回文件内容
write(writefd,buff,n);
}
close(fd);
}
}
intmain(intargc,char**argv)
{
intreadfd,writefd;
pid_tchildpid;
//创建两个有名管道
mkfifo(FIFO1,FILE_MODE);
mkfifo(FIFO2,FILE_MODE);
readfd=open(FIFO1,O_RDONLY,0);
writefd=open(FIFO2,O_WRONLY,0);
server(readfd,writefd);
return0;
}
voidclient(intreadfd,intwritefd)
{//客户
size_tlen;
ssize_tn;
charbuff[MAXLINE];
fgets(buff,MAXLINE,stdin);//读入路径名
len=strlen(buff);
if(buff[len-1]=='/n')//去掉结尾处的行符
len--;
write(writefd,buff,len);//写入管道
while((n==read(readfd,buff,MAXLINE))>0)//从管道读入数据
write(STDOU_FILENO,buff,n);//输出
}
intmain(intargc,char**argv)
{
intreadfd,writefd;
pid_tchildpid;
//创建两个有名管道
mkfifo(FIFO1,FILE_MODE);
mkfifo(FIFO2,FILE_MODE);
readfd=open(FIFO1,O_RDONLY,0);
writefd=open(FIFO2,O_WRONLY,0);
server(readfd,writefd);
writefd=open(FIFO1,O_WRONLY,0);
readfd=open(FIFO2,O_RDONLY,0);
client(readfd,writefd);
close(readfd);
close(writefd);
//删除有名管道
unlink(FIFO1);
unlink(FIFO2);
return0;
}
8,能通过两种方式设置为非阻塞:
1)调用open时指定O_NONBLOCK标志。
2)若描述字已经打开,用fcntl来enable掉O_NONBLOCK标志,对于管道来说,必须这样,因为它没有open调用,在pipe调用中也无法指定O_NONBLOCK标志,代码如下:
intflags;
flags=fcntl(fd,F_GETFL,0);
flags|=O_NONBLOCK;
fcntl(fd,F_SETFL,flags);
9,单进程服务器,多客户端
服务器代码:
intmain(intargc,char**argv)
{
intreadfifo,writefifo,dummyfd,fd;
char*ptr,buff[MAXLINE],fifoname[MAXLINE];
pid_tpid;
ssize_tn;
mkfifo(SERV_FIFO,FILE_MODE);
readfifo=open(SERV_FIFO,O_RDONLY,0);//服务器的读管道
dummyfd=open(SERV_FIFO,O_WRONLY,0);//写管道,没使用,开启为了防止服务器管道重复打开,关闭
while((n=readline(readfifo,buff,MAXLINE))>0)
{
if(buff[n-1]=='/n')n--;
buff[n]='/0';
if((ptr=strchr(buff,''))==NULL)
{
err_msg("请求命令错误");
continue;
}
*ptr++=0;
pid=atoi(buff);//获取客户端进程号
snprintf(fifoname,sizeof(fifoname),"/tmp/fifo.%ld",(long)pid);
writefifo=open(fifoname,O_WRONLY,0);//打开客户端管道的写端
if(fd=open(ptr,O_RDONLY,0))<0)
{//读文件失败
snprintf(buff+n,sizeof(buff)-n,"can'topen,%s/n",strerror(errno));
n=strlen(ptr);
write(writefifo,ptr,n);//往客户端管道写数据
close(writefifo);
}
else
{
while((n=read(fd,buff,MAXLINE))>0)
{
write(writefifo,buff,n);
}
close(fd);
close(writefifo);
}
}
return0;
}
客户端代码:
intmain(intargc,char**argv)
{
intreadfifo,writefifo;
size_tlen;
ssize_tn;
char*ptr,buff[MAXLINE],fifoname[MAXLINE];
pid_tpid;
pid=getpid();//获取当前进程ID
snprintf(fifoname,sizeof(fifoname),"/tmp/fifo.%ld",(long)pid);
mkfifo(fifoname,FILE_MODE);//创建客户端管道
snprintf(buff,sizeof(buff),"%ld",(long)pid);
len=strlen(buff);
ptr=buff+len;
//读入文件路径名
fgets(ptr,MAXLINE-len,stdin);
len=strlen(buff);
writefifo=open(SERV_FIFO,O_WRONLY,0);//打开服务器的写管道/
write(writefifo,buff,len);//给服务器传送指定格式的命令字
readfifo=open(fifoname,O_RDONLY,0);/打开客户端读管道
while((n=read(readfifo,buff,MAXLINE))>0)
{
write(STDOUT_FILENO,buff,n);//输出
}
close(readfifo);//关闭读端
unlink(fifoname);//删除管道
return0;
}
但是这个程序会导致DoS攻击,因为服务器会一直阻塞在对客户端FIFO的open调用中,若客户端不打开此FIFO来读,则服务器会一直阻塞,因此客户很容易通过阻止发送封包来使得服务器垮掉,解决办法有很多,可以一个客户一个进程,或一个客户一个线程,或使用进程池,或线程池。
10,UNIX默认的I/O模型是字节流模型,也就是不存在记录边界,一般有3种技巧来改造:
1)带内特殊终止序列:很多使用换行符来分隔每个消息,写入进程给每个消息加入一个换行符,读出进程每次读出一行,但缺点是分隔符要进行转义处理。如:FTP,SMTP等就使用一个回车后跟一个换行符来分隔记录。
2)显示长度:记录前加入其长度。
3)一次连接一个记录,通过关闭与对方的连接来指示一个记录结束,例如HTTP1.0
#include"unpipc.h"
#defineMAXMESGDATA(PIPE_BUF-2*sizeof(long))
#defineMESGHDRSIZE(sizeof(structmymesg)-MAXMESGDATA)
structmymesg
{
longmesg_len;//消息长度
longmesg_type;//消息类型
longmesg_data[MAXMESGDATA];//数据域
};
size_tmesg_send(intfd,structmymesg*mptr)
{
return(write(fd,mptr,MESGHDRSIZE+mptr->mesg_len));
}
ssize_tmesg_recv(intfd,structmymesg*mptr)
{
size_tlen;
ssize_tn;
if((n=read(fd,mptr,MESGHDRSIZE))==0)
{
return0;
}
elseif(n!=MESGHDRSIZE)
err_quit("头部错误");
if((len=mptr->mesg_len)>0)
{
if((n=read(fd,mptr->mesg_data,len))!=len)
err_quit("数据错误");
}
returnlen;
}
voidclient(intreadfd,intwritefd)
{//客户
size_tlen;
ssize_tn;
structmymesgmesg;
charbuff[MAXLINE];
fgets(mesg.mesg_data,MAXMESGDATA,stdin);//读入路径名
len=strlen(mesg.mesg_data);
if(mesg.mesg_data[len-1]=='/n')//去掉结尾处的行符
len--;
mesg.mesg_len=len;
mesg.mesg_type=1;
mesg_send(writefd,&mesg);
while((n==mesg_recv(readfd,&mesg))>0)//从管道读入数据
write(STDOU_FILENO,mesg.mesg_data,n);//输出
}
voidserver(intreadfd,intwritefd)
{//服务器
intfd;
ssize_tn;
charbuff[MAXLINE+1];
FIFL*fp;
structmymesgmesg;
mesg.mesg_type=1;
if((n==mesg_recv(readfd,&mesg))>0)//从管道读入数据
mesg.mesg_data[n]='/0';
if((fd=fopen(mesg.mesg_data,"r"))==NULL)
{//给客户端返回出错信息
snprintf(mesg.mesg_data+n,sizeof(mesg.mesg_data)-n,"can'topen,%s/n",strerror(errno));
mesg.mesg_len=strlen(mesg.mesg_data);
mesg_send(writefd,&mesg);
}
else
{
while(fgets(mesg.mesg_data,MAXMESGDATA,fp))!=NULL)
{//给客户端返回文件内容
mesg.mesg_len=strlen(mesg.mesg_data);
mesg_send(writefd,&mesg);
}
fclose(fp);
}
mesg.mesg_len=0;
mesg_send(writefd,&mesg);
}
分享到:
相关推荐
unix网络编程卷2第二版英文版 unix网络编程卷2第二版英文版 unix网络编程卷2第二版英文版 unix网络编程卷2第二版英文版 unix网络编程卷2第二版英文版 unix网络编程卷2第二版英文版 unix网络编程卷2第二版英文版 unix...
UNIX网络编程卷1代码.rarUNIX网络编程卷1代码.rar
《UNIX网络编程》(第1卷)(套接口API第3版)第1版和第2版由已故UNIX网络专家W. Richard Stevens博士独自编写。《UNIX网络编程》(第1卷)(套接口API第3版)是3版,由世界著名网络专家Bill Fenner和Andrew M. Rudoff执笔,...
unix网络编程第2版(1 2卷).pdf UNIX网络编程卷1:套接字联网API(第3版).pdf UNIX网络编程 卷2:进程间通信(第2版).pdf 计算机网络(第七版)复习题答案与课本对应.doc 计算机网络(第7版)-谢希仁.pdf
卷2:进程间通信(第2版)》是一部UNIX网络编程的经典之作!进程间通信(IPC)几乎是所有Unix程序性能的关键,理解IPC也是理解如何开发不同主机间网络应用程序的必要条件。《UNIX网络编程.卷2:进程间通信(第2版)》从对...
UNIX环境高级编程高清版_PDF版 + UNIX网络编程卷1高清版_PDF版
unix网络编程卷2,介绍的内容很全面,很适合刚接触linux或者unix网络编程开发人员学习
UNIX网络编程 卷2
unix网络编程-第三版读书笔记unix网络编程-第三版读书笔记
笔记_UNIX环境网络编程卷二进程间通信_中文第二版
UNIX 网络编程卷 2 进程间通信读书笔记(一)
unix网络编程读书笔记unix网络编程读书笔记unix网络编程读书笔记unix网络编程读书笔记unix网络编程读书笔记
《LINUX与UNIX SHELL编程指南》读书笔记-二次发布版
Unix网络编程卷一.pdf Unix网络编程卷一.pdf Unix网络编程卷一.pdf
《UNIX网络编程 卷1:套接字联网API(第2版)》是一部UNIX网络编程的经典之作。书中全面深入地介绍了如何使用套接字API进行网络编程。全书不但介绍了基本编程内容,还涵盖了与套接字编程相关的高级主题,对于客户/...
UNIX网络编程随书源代码(包含卷一卷二)
UNIX网络编程卷1(第三版 英文版).pdf
( UNIX网络编程 卷2:进程间通信(第2版)中文PDF版,网络编程基础
改资源是zip压缩包,里面包括: UNIX网络编程(第2版)卷1:套接口API和XOpen.传输接口API.pdf UNIX网络编程(第2版)卷2:进程间通信.pdf