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

本文介绍了Linux系统下的信号量机制及其编程实现,包括信号量的创建、初始化、操作及删除过程。此外,还详细讲解了网络编程的基础知识,如IP地址的表示与转换、网络配置、TCP/UDP编程特点及其实现案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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(阻塞)    -(解除阻塞)

#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.删除(可以不删除)

}

#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  //把字符串转换为structin_addr;(网络字结序)
   
   #inet_network//把字符串转换为整数(本地字节序)
   
   inet_ntoa  //把结构体转换为字符串
   
   htons
   htonl
   
   ntohs
   ntohl

#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

#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();

}

#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]);

}   

#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     接收数据并打印
   返发一个信息       

#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,

                (structsockaddr*)&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);

}

#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,

                (structsockaddr*)&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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值