一.基于文件的通信
1.普通文件(io/mmap)
2.有名管道文件
3.匿名管道
4.Socket
二.基于內存的通信
0.一組內核內存的工具
ipcs
ipcs -m
ipcs -q
ipcs -s
ipcrm -q 編號ID
1.普通的父子進程之間的匿名內存共享映射
2.內核共享內存
編程模型
2.1.創建共享內存,得到一個ID shmget
2.2.把ID映射成虛擬地址(把內核中的緩存連接到用戶進程) shmat
2.3.使用虛擬地址訪問內核共享內存 使用任何內存函數與運算符號
2.4.卸載虛擬地址 shmdt
2.5.刪除共享內存 shctl(修改/獲取共享內存的屬性)
共享內存的屬性
案例:
A.創建共享內存,并且修改內存數據。
1.創建共享內存
int shmget(key_t key,//為什么需要key
int size,//共享內存大小
int flags//共享內存的屬性與權限
)
為什么要key_t: 約定創建與訪問的是同一個共享內存。 第三個參數: 方式|權限 方式:創建 IPC_CREAT IPC_EXCL 打開:0 常見的兩種方式: 創建:IPC_CREAT|IPC_EXCL | 0666; 打開:0 返回: 成功返回共享內存ID 失敗返回-1 B.根據ID得到共享,并且訪問內存數據。 void shmat(int id,
void *startaddr,//0:系統指定首地址
int flags)//掛載方式,建議0,可以使用IPC_RDONLY
C.刪除 int shmctl(int id,//被操作的共享內存ID
int how,//操作方式:一共三種操作
struct shmid_ds*ds)//共享內存屬性
how: IPC_STAT IPC_SET IPC_RMID
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/shm.h>
#include <sys/ipc.h>
key_t key;
int shmid;
int *p;
int i=0;
void deal(int s)
{
if(s==SIGINT)
{
//4.卸載共享內存shmdt
shmdt(p);
//5.刪除共享內存shctl
shmctl(shmid,IPC_RMID,0);
exit(0);
}
}
main()
{
signal(SIGINT,deal);
//1.創建共享內存shmget
key=ftok(".",255);
if(key==-1) printf("ftok error:%m\n"),exit(-1);
shmid=shmget(key,4,IPC_CREAT|IPC_EXCL|0666);
if(shmid==-1) printf("get error:%m\n"),exit(-1);
//2.掛載共享內存shmat
p=shmat(shmid,0,0);
if(p==(int*)-1) printf("at error:%m\n"),exit(-1);
//3.訪問共享內存
while(1)
{
*p=i;
sleep(1);
i++;
}
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/shm.h>
#include <sys/ipc.h>
key_t key;
int shmid;
int *p;
void deal(int s)
{
if(s==2)
{
//4.卸載共享內存shmdt
shmdt(p);
exit(0);
}
}
main()
{
signal(SIGINT,deal);
//1.創建共享內存shmget
key=ftok(".",255);
if(key==-1) printf("ftok error:%m\n"),exit(-1);
shmid=shmget(key,4,0);
if(shmid==-1) printf("get error:%m\n"),exit(-1);
//2.掛載共享內存shmat
p=shmat(shmid,0,0);
if(p==(int*)-1) printf("at error:%m\n"),exit(-1);
//3.訪問共享內存
while(1)
{
sleep(1);
printf("%d\n",*p);
}
}
3.內核共享隊列(有序) 編程模型: 3.1.創建共享隊列/得到隊列msgget 3.2.使用隊列(發送消息msgsnd/接收消息msgrcv) 3.3.刪除隊列msgctl案例: A:創建共享隊列 int msgget(key_t,int); B:發送消息 int msgsnd(
int id,//消息隊列ID
const void *msg,//要發送消息
size_t len,//消息的長度
int flags//發送消息的方式0或者IPC_NOWAIT,建議為0
);
返回: -1:失敗 0:成功 第二個參數的消息有固定的格式 4字節:表示消息的類型 若干字節:消息內容。 第三個參數: 消息的大小,不包含類型的4個字節
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct msgbuf
{
long type;
char data[32];
};
main()
{
key_t key;
int msgid;
int i;
struct msgbuf msg;
//1創建消息隊列
key=ftok(".",200);
if(key==-1) printf("ftok err:%m\n"),exit(-1);
msgid=msgget(key,0/*IPC_CREAT|IPC_EXCL|0666*/);
if(msgid==-1)printf("get err:%m\n"),exit(-1);
//2構造消息
//3發送消息
for(i=1;i<=10;i++)
{
bzero(msg.data,sizeof(msg.data));
msg.type=1;
sprintf(msg.data,"MessageI:%d",i);
msgsnd(msgid,&msg,sizeof(msg.data),0);
}
for(i=1;i<=10;i++)
{
bzero(msg.data,sizeof(msg.data));
msg.type=2;
sprintf(msg.data,"MessageII:%d",i);
msgsnd(msgid,&msg,sizeof(msg.data),0);
}
//4刪除隊列
//msgctl(msgid,IPC_RMID,0);
}
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct msgbuf
{
long type;
char data[32];
};
main()
{
key_t key;
int msgid;
int i;
struct msgbuf msg;
//1得到消息隊列
key=ftok(".",200);
if(key==-1) printf("ftok err:%m\n"),exit(-1);
msgid=msgget(key,0);
if(msgid==-1)printf("get err:%m\n"),exit(-1);
//2構造消息
//3接收消息
while(1)
{
bzero(&msg,sizeof(msg));
msg.type=2;
msgrcv(msgid,&msg,sizeof(msg.data),2,0);
printf("%s\n",msg.data);
}
}
三.基于socket文件的IPC socket文件的通信方式,比較重要,原因:網絡采用這種通信模型。 兩種模型: 對等模型 C/S模型 1.對等模型: 1.建立socket:socket int socket(
int domain,//地址族的類型AF_UNIX AF_INET
int type,//支持的數據格式:流SOCK_STREAM/報文SOCK_DGRAM
int protocol);//支持的協議,建議為0
返回值: 成功返回文件描述符號。 失敗返回-1; 2.綁定在地址上(文件目錄地址)URL(Universe Resource Location) 協議://路徑/文件名 file:///usr/bin/ls http://192.168.0.72/index.php struct sockaddr; struct sockaddr_un;un=unix struct sockaddr_in;in=internet int bind(int fd,//socket描述符號
struct sockaddr*addr,//綁定地址
socklen_t size);//地址長度
3.接收數據 read/recv/recvfrom 4.關閉socket
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/un.h>
main()
{
int fd;
int r;
char buf[200];
//1.建立socket
fd=socket(AF_UNIX,SOCK_DGRAM,0);
if(fd==-1) printf("socket err:%m\n"),exit(-1);
printf("socket成功!\n");
//2.構造本地文件地址
struct sockaddr_un addr={0};
addr.sun_family=AF_UNIX;
memcpy(addr.sun_path,"my.sock",
strlen("my.sock"));
//3.把socket綁定在地址上
r=bind(fd,(struct sockaddr*)&addr,sizeof(addr));
if(r==-1) printf("bind err:%m\n"),exit(-1);
printf("地址綁定成功!\n");
//4.接收數據
while(1)
{
bzero(buf,sizeof(buf));
r=read(fd,buf,sizeof(buf));
buf[r]=0;
printf("%s\n",buf);
}
//5.關閉
close(fd);
//6.刪除socket文件
unlink("my.sock");
}
1.建立socket:socket 2.連接到目標:connect(可選) 3.發送數據:write/send/sendto 4.關閉close
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/un.h>
#include <string.h>
#include <unistd.h>
main()
{
int fd;
int r;
char buf[100];
struct sockaddr_un addr={0};
//1.建立socket
fd=socket(AF_UNIX,SOCK_DGRAM,0);
//2.連接到指定的地址
addr.sun_family=AF_UNIX;
memcpy(addr.sun_path,"my.sock",
strlen("my.sock"));
r=connect(fd,(struct sockaddr*)&addr,
sizeof(addr));
//3.發送數據
while(1)
{
write(fd,"Hello!MaomaoYu!",
strlen("Hello!MaomaoYu!"));
sleep(1);
}
//4.關閉
close(fd);
}
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//1.
#include <netinet/in.h>
#include <arpa/inet.h>
main()
{
int fd;
int r;
char buf[200];
//1.建立socket
//2
fd=socket(AF_INET,SOCK_DGRAM,0);
if(fd==-1) printf("socket err:%m\n"),exit(-1);
printf("socket成功!\n");
//2.構造本地文件地址
//3.
struct sockaddr_in addr={0};
addr.sin_family=AF_INET;
addr.sin_port=htons(9999);
addr.sin_addr.s_addr=
inet_addr("192.168.180.92");
//3.把socket綁定在地址上
r=bind(fd,(struct sockaddr*)&addr,sizeof(addr));
if(r==-1) printf("bind err:%m\n"),exit(-1);
printf("地址綁定成功!\n");
//4.接收數據
while(1)
{
bzero(buf,sizeof(buf));
r=read(fd,buf,sizeof(buf));
buf[r]=0;
printf("%s\n",buf);
}
//5.關閉
close(fd);
//6.刪除socket文件
unlink("my.sock");
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
//1
#include <netinet/in.h>
#include <arpa/inet.h>
main()
{
int fd;
int r;
//2
struct sockaddr_in addr={0};
//1.建立socket
//3
fd=socket(AF_INET,SOCK_DGRAM,0);
//2.連接到指定的地址
//4
addr.sin_family=AF_INET;
addr.sin_port=htons(9999);
addr.sin_addr.s_addr
=inet_addr("192.168.180.92");
r=connect(fd,(struct sockaddr*)&addr,
sizeof(addr));
//3.發送數據
write(fd,"Hello!Maomaochong!",
strlen("Hello!Maomaochong!"));
//4.關閉
close(fd);dd
}
2.C/S模型 Server Client 建立socket:socket 建立socket:socket 綁定地址:bind 建立連接:connect 監聽:listen 接收:accept read/write read/write close close int listen(int fd,int num); 0:監聽成功 -1:失敗int accept(int fd,
struct sockaddr*addr,//返回連接著的地址
socklen_t* len)//接收返回地址的緩沖長度
返回: -1:接收失敗 >=0:對應客戶的文件描述符號
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/un.h>
main()
{
int sfd;
int cfd;
struct sockaddr_un addr;
int r;
char buf[100];
//1.建立socket
sfd=socket(AF_UNIX,SOCK_STREAM,0);
if(sfd==-1) printf("socket err:%m\n"),exit(-1);
printf("建立socket成功!\n");
//2.綁定地址
bzero(&addr,sizeof(addr));
addr.sun_family=AF_UNIX;
memcpy(addr.sun_path,"cs.sock",
strlen("cs.sock")+1);
r=bind(sfd,(struct sockaddr*)&addr,sizeof(addr));
if(r==-1) printf("bind err:%m\n"),exit(-1);
printf("bind成功!\n");
//3.監聽
r=listen(sfd,10);
if(r==-1) printf("listen err:%m\n"),exit(-1);
printf("listen成功!\n");
//4.接收客戶
cfd=accept(sfd,0,0);
if(cfd==-1) printf("accept err:%m\n"),exit(-1);
printf("建立連接者的狀態成功!\n");
//5.接收這個客戶的數據
while(1)
{
r=read(cfd,buf,sizeof(buf));
if(r==0)
{
printf("連接者退出");
break;
}
if(r==-1)
{
printf("scoket故障!\n");
break;
}
buf[r]=0;
printf("::%s\n",buf);
write(cfd,"Hi",2);
}
//6.關閉客戶
close(cfd);
//7.關閉整個socket
close(sfd);
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/un.h>
#include <string.h>
#include <unistd.h>
main()
{
int fd;
int r;
char buf[100];
struct sockaddr_un addr={0};
//1.建立socket
//fd=socket(AF_UNIX,SOCK_DGRAM,0);
fd=socket(AF_UNIX,SOCK_STREAM,0);
//2.連接到指定的地址
addr.sun_family=AF_UNIX;
memcpy(addr.sun_path,"cs.sock",
strlen("cs.sock"));
r=connect(fd,(struct sockaddr*)&addr,
sizeof(addr));
//3.發送數據
while(1)
{
write(fd,"Hello!MaomaoYu!",
strlen("Hello!MaomaoYu!"));
read(fd,buf,100);
printf("%s\n",buf);
sleep(1);
}
//4.關閉
close(fd);
}
總結:
共享內存
共享隊列
socket文件通信
課堂練習:
CS模型代碼
CS模型把socket文件替換成IP地址
課后作業:
模仿課堂案例獨立完成
1.共享內存
2.共享隊列
3.socket對等模型
4.socket的CS模型