zoukankan      html  css  js  c++  java
  • linux高级编程day09 笔记

    一.信号量(同步)
     1.回顾:
       一个进程控制另外一个进程.
       逻辑变量+pause/sleep+信号
     2.信号量(semaphore)信号灯
      三个数据:红灯/绿灯/黄灯    
            60   90   10
      信号量是共享内存整数数组.根据需要定义指定的数组长度
      信号量就是根据数组中的值,决定阻塞还是解除阻塞
     
     3.编程
       3.1.创建或者得到信号量     semget
       3.2.初始化信号量中指定下标的值 semctl
       3.3.根据信号量阻塞或者解除阻塞 semop
       3.4.删除信号量         semctl
    案例:
       A:             B
       创建信号量        得到信号量
       初始化信号量      
       根据信号量阻塞     解除阻塞
       删除信号量       
        
       semget函数说明

    int semget(key_t key,
            int nums,//信号量数组个数
            int flags);//信号量的创建标记
                                    //创建IPC_CREAT|IPC_EXCL|0666
                                    //打开0

       返回:  -1:失败
          >=0:成功返回信号量的ID

    int semop(
            int semid,//信号量ID
            struct sembuf *op,//对信号量的操作.操作可以是数组多个
            size_t nums,//第二个参数的个数
        );

       返回:
         -1:时失败
          0:成功 

    int semctl(int semid,
                int nums,//对IPC_RMID无意义
                int cmd,//SETVAL  IPC_RMID
                ...);//对IPC_RMID无意义
    struct  sembuf 
    {
        int sem_num;//下标
        int sem_op;
        int sem_flg;//建议为0.
    }

       sem_op:
         前提条件信号量是unsigned short int;
         不能<0.
         -:够减,则semop马上返回,不够减,则阻塞.
         +:执行+操作
         0:判定信号量>0,则阻塞,直到为0
       控制进程的搭配方式:
          +(解除阻塞) -(阻塞)
          0(阻塞)     -(解除阻塞)

    View Code
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    //2.1.定义一个联合体
    union semun {
        int    val;
        struct semid_ds *buf;
        unsigned short  *array;
        struct seminfo  *__buf;
    };
    
    main()
    {
        key_t key;
        int semid;    //信号量ID
        union  semun v;//2.2.定义初始化值
        int r;
        struct sembuf op[1];
        //1.创建信号量
        key=ftok(".",99);
        if(key==-1) printf("ftok err:%m\n"),exit(-1);
        
        //semid=semget(key,1/*信号量数组个数*/,
        //        IPC_CREAT|IPC_EXCL|0666);
                
        semid=semget(key,1,0);//得到信号量
        if(semid==-1) printf("get err:%m\n"),exit(-1);
        
        printf("id:%d\n",semid);
        //2.初始化信号量
        v.val=2;
        r=semctl(semid,0,SETVAL,v);//2.3设置信号量的值
        if(r==-1) printf("初始化失败!\n"),exit(-1);
    
        //3.对信号量进行阻塞操作
        //3.1.定义操作
        op[0].sem_num=0;//信号量下标
        op[0].sem_op=-1;//信号量操作单位与类型
        op[0].sem_flg=0;
        while(1)
        {
            r=semop(semid,op,1);
            printf("解除阻塞!\n");
        }
        
        //4.删除(可以不删除)
    }
    View Code
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    //2.1.定义一个联合体
    union semun {
        int    val;
        struct semid_ds *buf;
        unsigned short  *array;
        struct seminfo  *__buf;
    };
    
    main()
    {
        key_t key;
        int semid;    //信号量ID
        union  semun v;//2.2.定义初始化值
        int r;
        struct sembuf op[2];
        //1.创建信号量
        key=ftok(".",99);
        if(key==-1) printf("ftok err:%m\n"),exit(-1);
        
                
        semid=semget(key,1,0);//得到信号量
        if(semid==-1) printf("get err:%m\n"),exit(-1);
        
        printf("id:%d\n",semid);        
        //3.对信号量进行阻塞操作
        //3.1.定义操作
        op[0].sem_num=0;//信号量下标
        op[0].sem_op=1;//信号量操作单位与类型
        op[0].sem_flg=0;
        op[1].sem_num=0;//信号量下标
        op[1].sem_op=1;//信号量操作单位与类型
        op[1].sem_flg=0;
        while(1)
        {
            r=semop(semid,op,2);
            sleep(1);
        }
        
        //4.删除(可以不删除)
        //semctl(semid,0,IPC_RMID);
    }

    二.网络
     1.基础(ip)
      1.1.网络工具
        ping
        ping ip地址
        ping -b ip广播地址
        ifconfig -a    
        
        netstat -a
        netstat -u
        netstat -t
        netstat -x
        netstat -n
        
        route
        lsof
      1.2.网络的基本概念
        网络编程采用socket模型.
        网络通信本质也是进程之间的IPC。
           是不同主机之间。
        
        识别主机:4字节整数:IP地址
        识别进程:2字节整数:端口号
          
        IP地址的表示方法: 内部表示:4字节整数
                   外部表示:数点字符串
                        结构体
          1 2 3 4  分段表示,每个段使用.分割
          "192.168.0.26"

        ip地址的转换:  

        struct  sockaddr_in
        {
            int                         sin_family;
            in_port_t             sin_port;
            struct in_addr     sin_addr;
            
        }
        struct in_addr
        {
            in_addr_t  s_addr;
        }    

        //总结:
          IP地址的表示
            字符串表示"192.168.0.26"
            整数表示:in_addr_t;
            字结构表示struct in_addr;
          连接点:endpoint

        struct sockaddr_in
        {
            in_port_t                 sin_port;
            struct in_addr       sin_addr;
        };

      1.3.IP地址的转换
       inet_addr   //把字符串转换为整数(网络字节序)
       inet_aton  //把字符串转换为struct in_addr;(网络字结序)
       
       #inet_network//把字符串转换为整数(本地字节序)
       
       inet_ntoa  //把结构体转换为字符串
       
       htons
       htonl
       
       ntohs
       ntohl

    View Code
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    main()
    {
        /*
        in_addr_t  nip=192<<24 | 168 <<16 | 0<<8  | 26;
        char  *ip="192.168.0.26";
        //把整数转换为字符串inet_ntoa
        struct in_addr sip;
        int myip;
        
        sip.s_addr=nip;
        
        printf("nip:%u\n",nip);
        
        printf("%s\n",inet_ntoa(sip));
        
        myip=inet_addr(ip);
        printf("%u\n",myip);
        
        printf("%hhu.%hhu.%hhu.%hhu\n",    myip>>24 & 255,
                                myip>>16 & 255,
                                myip>>8  & 255,
                                myip>>0  & 255);
        */
        /*
        char ip[4]={192,168,0,26};
        printf("%d\n",*(int*)ip);
        */
        char *ip="10.45.8.1";
        struct in_addr addr;
        in_addr_t net;
        in_addr_t host;
        struct in_addr tmp;
        
        inet_aton(ip,&addr);
        net=inet_lnaof(addr);
        host=inet_netof(addr);
        
        tmp.s_addr=net;
        
        printf("%s\n",inet_ntoa(tmp));
        
        tmp.s_addr=host;
        printf("%s\n",inet_ntoa(tmp));
    }

      1.4.IP地址的意义 
       IP地址的位表达不同意义:
         IP地址组建网络:网络标识/主机标识
              网络     主机
       A类     7         24    网络少  主机
       B类     14         16      
       C类     21          8 
       D类     组播 
       E类     没有使用
       
      1.5.计算机系统中的网络配置
       /etc/hosts文件  配置IP,域名,主机名
          gethostbyname
          gethostbyaddr
       /etc/protocols文件  配置系统支持的协议
       /etc/services文件 配置服务   
       get***by***;   
       gethostbyname   
       getprotobyname

    View Code
    #include <stdio.h>
    #include <netdb.h>
    main()
    {
        struct hostent *ent;
        /*打开主机配置数据库文件*/
        sethostent(1);
        while(1)
        {
            ent=gethostent();
            if(ent==0) break;
            
            printf("主机名:%s\t",ent->h_name);
            printf("IP地址:%hhu.%hhu.%hhu.%hhu\t",
                    ent->h_addr[0],
                    ent->h_addr[1],
                    ent->h_addr[2],
                    ent->h_addr[3]);
            printf("别名:%s\n",ent->h_aliases[0]);
        }
        endhostent();
    }
    View Code
    #include <stdio.h>
    #include <netdb.h>
    main()
    {
        struct hostent *ent;
        ent=gethostbyname("bbs.tarena.com.cn");
        //printf("%s\n",ent->h_aliases[0]);
        printf("%hhu.%hhu.%hhu.%hhu\n",
            ent->h_addr_list[0][0],
            ent->h_addr_list[0][1],
            ent->h_addr_list[0][2],
            ent->h_addr_list[0][3]);
    }    
    View Code
    #include <stdio.h>
    #include <netdb.h>
    #include <sys/utsname.h>
    main()
    {
        struct protoent *ent;
        struct utsname name;
        ent=getprotobyname("tcp");
        printf("%d\n",ent->p_proto);
        
        uname(&name);
        printf("%s\n",name.machine);
        printf("%s\n",name.nodename);
        printf("%s\n",name.sysname);
        printf("%s\n",name.domainname);
    }

     2.TCP/UDP编程
       对等模型:AF_INET   SOCK_DGRAM    0:UDP
       C/S 模型:AF_INET  SOCK_STREAM   0:TCP
      2.0.网络编程
        ISO的7层模型:
           物理层     
           数据链路层   数据链路层(数据物理怎么传输)
           网络层     IP层   (数据的传输方式)
           传输层     传输层   (数据传输的结果)     
           会话层     应用层   (数据传递的含义)
           表示层
           应用层
            
      2.1.UDP编程的数据特点
        UDP采用对等模型SOCK_DGRAM
        socket            socket:socket
        绑定IP地址bind        连接目标(可选)  conncect
        read/recv/recvfrom      发送数据 write/send/sendto
        关闭close   
    案例:
      A:                    B
       接收用户的数据         发送数据
       打印数据与发送者IP     接收数据并打印
       返发一个信息       

    View Code
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    main()
    {
        int fd;//socket描述符号
        struct sockaddr_in ad;//本机的IP地址
        char buf[100];//接收数据缓冲
        
        struct sockaddr_in ad_snd;//发送者IP地址
        socklen_t len;//发送者IP的长度
        int r;
        
        fd=socket(AF_INET,SOCK_DGRAM,17);
        if(fd==-1) printf("socket:%m\n"),exit(-1);
        printf("建立socket成功!\n");
        
        ad.sin_family=AF_INET;
        ad.sin_port=htons(11111);
        inet_aton("192.168.180.92",&ad.sin_addr);
        r=bind(fd,(struct sockaddr*)&ad,sizeof(ad));
        if(r==-1) printf("bind err:%m\n"),exit(-1);
        printf("绑定成功!\n");
        
        while(1)
        {
            len=sizeof(ad_snd);
            r=recvfrom(fd,buf,sizeof(buf)-1,0,
                    (struct sockaddr*)&ad_snd,&len);
            if(r>0){
                buf[r]=0;
                printf("发送者IP:%s,端口:%hu,数据:%s\n",
                    inet_ntoa(ad_snd.sin_addr),
                    ntohs(ad_snd.sin_port),buf);
                sendto(fd,"古怪!",strlen("古怪!"),0,
                (struct sockaddr*)&ad_snd,sizeof(ad_snd));
            }
            if(r==0)
            {
                printf("关闭!\n");            
                break;
            }
            if(r==-1)
            {
                printf("网络故障!\n");            
                break;
            }
        }
        
        close(fd);
    }
    View Code
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <netdb.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    main()
    {
        int fd;
        struct sockaddr_in ad;
        char buf[101];
        int r;
        
        fd=socket(AF_INET,SOCK_DGRAM,0);
        if(fd==-1) printf("socket err:%m\n"),exit(-1);
        
        ad.sin_family=AF_INET;
        ad.sin_port=htons(11111);
        ad.sin_addr.s_addr=inet_addr("192.168.180.92");    
        //connect(fd,(struct sockaddr*)&ad,sizeof(ad));
        while(1)
        {
            r=read(0,buf,sizeof(buf)-1);
            if(r<=0) break;
            
            buf[r]=0;
            
            r=sendto(fd,buf,r,0,
                    (struct sockaddr*)&ad,sizeof(ad));
            
            bzero(buf,sizeof(buf));
            r=recv(fd,buf,sizeof(buf),0);
            buf[r]=0;
            printf("来自接收方的数据:%s\n",buf);
            //r=send(fd,buf,r,0);        
            if(r==-1) break;
            
        }
        close(fd);
    }    

      总结:
        1.问题:
          connect + send  == sendto
        2.问题:
          recvfrom的作用不是专门从指定IP接收
          而是从任意IP接收数据,返回发送数据者的IP
        3.问题:
          为什么要bind,bind主要目的告诉网络发送数据的目标.
          是否一定绑定才能发送数据?
          否:只要知道你的IP与PORT,就能发送数据.
        4.问题:
          为什么发送者没有绑定IP与端口,他也有端口?
          底层网络驱动,帮我们自动生成IP与端口.
        5.缺陷:
          接收方不区分发送者的.  
            
     send函数  
     sendto函数

    int sendto(
            int fd,//socket描述符号
            const void *buf,//发送的数据缓冲
            size_t size,//发送的数据长度
            int flags,//发送方式MSG_NOWAIT MSG_OOB
            const struct sockaddr *addr,//发送的目标的IP与端口
            socklen_t len//sockaddr_in的长度
        );

       返回:
         -1:发送失败
         >=0:发送的数据长度
     recv函数
     recvfrom函数 

    int recvfrom(
            int fd,
            void *buf,
            size_t size,
            int flags,
            struct sockaddr*addr,//返回发送者IP与端口
            socklen_t *len);//输入返回IP的缓冲大小,返回实际IP的大小                            

      2.2.TCP编程的数据特点
      2.3.TCP服务器的编程
     3.TCP的服务器编程模型
     4.IP协议与处理(SOCK_RAW,SOCK_PACKET)
     5.pcap编程
     6.HTTP协议与网页搜索
     
    作业:
      1.重新编写UDP网络通信 
      2.使用gethostbyname的得到bbs.tarena.com.cn
                   www.sina.com

  • 相关阅读:
    支付宝在ios应用上的开发[转]
    检查设备摄像头、指南针、录像、陀螺仪的状态
    iOS APP AppIcon& LaunchImage
    Crashlytics功能集成
    Email-Ext Plugin install ------ Jenkins Plugins
    瑜伽第一篇
    iOS Font
    导出android真机上应用的apk文件
    生成一个ipa的包,使非开发机也能安装成功 (Xcode5.1)
    How to use Jenkins
  • 原文地址:https://www.cnblogs.com/tangzhengyue/p/2651027.html
Copyright © 2011-2022 走看看