linux高階程式設計day08 筆記 (轉)
阿新 • • 發佈:2018-12-27
一.基於檔案的通訊
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.建立共享記憶體
約定建立與訪問的是同一個共享記憶體。
第三個引數:
方式|許可權
方式:建立 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_RDONLYC.刪除
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模型