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

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

struct  sembuf 
{
    int sem_num;//下標    int sem_op;
    int sem_flg;//建議為0.}一.訊號量(同步)
 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無意義  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   //把字串IP轉換為二進位制整數IP(網路位元組序)
   inet_aton  //把字串IP轉換為struct in_addr;(網路字結序)
   #inet_network//把字串IP轉換為二進位制整數IP(本地位元組序)
   inet_ntoa  //把結構體struct in_addr轉換為字串IP
  4個本地主機位元組序與網路序轉換函式:
  h表示主機位元組序,n表示網路位元組序,s表示兩個2位元組,l表示4個位元組
uint16_thtons(uint16_t)
uint32_thtonl(uint32_t)
uint16_tntohs(uint16_t)
uint32_tntohl(uint32_t)
   ps:所以傳送時候,埠轉換可以用htons,而ip可以用htonl

#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,
                (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);
} 總結:
    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