c++ 学习笔记(高级linux编程) day8

本文详细介绍了Linux高级编程中的文件通信技术,包括基于文件的通信方式(如普通文件、有名管道、匿名管道和Socket)及内核共享内存,以及Socket文件通信的对等模型和C/S模型。通过实例代码展示了如何实现共享内存、共享队列和Socket通信。

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:创建共享队列
     intmsgget(key_t,int);      
   B:发送消息

   int msgsnd(

           int id,//消息队列ID

           const void *msg,//要发送消息

           size_t len,//消息的长度

           int flags//发送消息的方式,建议为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_UNIXAF_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模型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值