1. 程式人生 > >linux高階程式設計day08 筆記 (轉)

linux高階程式設計day08 筆記 (轉)

一.基於檔案的通訊
  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_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模型