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_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模型

你可能感兴趣的:(linux高级编程day08 笔记 )