網絡編程總結


基本知識:
1.協議
【作用】:使交換信息的兩個部分之間相互理解的一組規則、
約定和數據結構的集合。
即:爲了使不同版本的計算機能相互溝通而存在
在現在的網絡應用中使用最廣泛的協議是TCP/IP協議

ISO
OSI【【七層協議】】模型
【1】.應用層:爲應用(程序提供服務)並(規定)應用程序中(通信的相關細節),
如:ftp,tftp,smtp,ssh,telnet...
【2】.表示層:主要負責數據格式的轉換(設備固有格式     <==>     網絡格式)
【3】.會話層:主要建立和斷開通信連接
【4】.傳輸層:起着可靠傳輸的作用
【5】.網絡層:將數據傳輸到目標地址,主要負責尋址和路由選擇
【6】.數據鏈路層:負責物理層面上的互連的節點之間的通信傳輸
【7】.物理層:負責0、1比特流與電壓的高低、光的閃滅之間的互換


根據七層協議模型,    tcp/IP協議可分爲四層
【1】.應用層:
【2】.傳輸層:        TCP        UDP
【3】.網絡層:        IPv4        IPv6
【4】.網絡接口層

2.常用協議
【1】.TCP協議
        傳輸控制協議,是一種【面向連接】的協議,類似打電話
【2】.UDP協議
        用戶數據報協議,是一種【無連接】的協議,類似發短信
【3】.IP協議
        互聯網協議,是上述兩種協議的底層協議,當需要【開發
        新的通信協議】時,才需要關注

3.IP地址
【作用】:作爲通信設備在互聯網中的唯一地址標識
【本質】:            1.由32位二進制組成的【整數】(IPv4)
                        2.由128位二進制組成的【整數】(IPv6)

日常生活中採用點分十進制表示法來描述IP地址,也就是將每個字節的
二進制轉爲十進制的整數,不同的整數之間用小數點分隔
    0x01020304        ==>1.2.3.4

    2^32個地址,怎麼管理?
    將【IP地址分爲兩部分】:網絡地址和主機地址
    【網絡地址】:屬於哪個網絡            【可以定位在哪個網吧上網】
    【主機地址】:網絡中主機的編號    【可以定位在哪臺電腦上網】                    
                        
    根據網絡地址和主機地址位數的不同分爲四類:
    A:    0 + 7位的網絡號 +     24位主機地址
        0.0.0.0   ~        127.255.255.255 
    B:    10 + 14位網絡號    +    16位主機地址
        128.0.0.0 ~        191.255.255.255 
    C:    110 + 21位網絡號    +    8位主機地址
        192.0.0.0 ~        223.255.255.255 
    D:    1110 + 28位多(組)播地址
        224.0.0.0 ~        239.255.255.255
    E:    備用
    
    查看IP地址的命令
    ipconfig
    ifconfig                    
                        
3.子網掩碼        【第一種分IP地址的方法】
【作用】:用於劃分IP地址中的網絡地址和主機地址,
                也可以用於判斷兩個IP是否在同一局域網中
    具體分法:        【IP地址】    跟 【子網掩碼】     做【與運算】    得到 【網絡地址】
    【前提是換成二進制】
    IP地址 & 子網掩碼 = 網絡地址
    例:
        172.30.100.64        IP
    &    255.255.255.0         子網掩碼
    --------------------------------
        172.30.100.0 ---網絡地址
                   64---主機地址
        
    
    例:
        IP:166.111.160.1 和    166.111.161.45
  子網掩碼:255.255.254.0 
    解析:
        166.111.160.1 
        255.255.254.0 &
        ---------------
        166.111.160    網絡號

        166.111.161.45 
        255.255.254.0 &
        ---------------
        166.111.160 網絡號
        
    總結:上面兩個IP地址在同一個局域網中
【第二種分IP地址的方法】:    
    斜槓'/'後面的數字N表示前N位爲網絡號
    166.111.160.1     /23     
    166.111.161.45    /23     
    23:表示前23位爲網絡號    
                            
4.端口號
    【IP地址】 -- 定位到具體的某一臺主機/設備            【推斷出你在哪個網吧哪臺機子上網】
    【端口號】 -- 定位到主機/設備上的某一個進程            【推斷出你在那臺機子玩什麼】
    本質上就是一個16位的無符號整數    unsigned short,範圍是0~65535
    其中0-1024之間的端口號被系統使用,建議【從5000開始使用】
                        
    【網絡編程】中需【要提供】兩個信息:【IP地址】+【端口號】                     
                        
5.字節序(多字節整數)
    小端模式:主要指將低位字節數據保存在低位內存地址的系統
    大端模式:主要指將低位字節數據保存在高位內存地址的系統
    【在準備通信地址和使用通信地址信息時需要注意類型的轉換】                    
                        
----------------------------------------------------------                        
網絡編程【又名socket編程,因爲要使用socket函數得到信息載體】                        
一、網絡編程又叫socket編程
【套接字概念】:是一個網絡編程的接口,是網絡數據傳輸的軟設備。
【套接字作用】:用於網絡交互。

【網絡編程本質】:編寫程序【使兩臺連網的計算機】相互【交換數據】。
    
unix/linux系統作爲服務器操作系統存在至今,因此,
Linux的網絡功能應該是非常全面和強大。    
網絡編程其實有很成熟的通信模型,並且windows也通用。
                        
二、通信模型(基於TCP的一對一的通信模型)                        
【1】.一對一服務器:

【等待連接原理】:
1 有人從很遠很遠的地方嘗試調用 connect()來連接你的機器上的某個端口
(當然是你已經在 listen()的)。
2 他的連接將被 listen 加入等待隊列等待 accept()函數的調用(加入等待隊
列的最多數目由調用 listen()函數的第二個參數 backlog 來決定)。
3 你調用 accept()函數,告訴他你準備連接。
4 accept()函數將返回一個新的套接字描述符,這個描述符就代表了這個連接!

好,這時候你有了【兩個套接字描述符】,返回給你的那個就是和遠程計算機的連接,
而第一個套接字描述符仍然在你的機器上原來的那個端口上 listen()。
這時候你所得到的那個新的套接字描述符就可以進行 send()操作和recv()操作了。    

    http://blog.csdn.net/wukui1008/article/details/7669173    【套接字】    
        【監聽套接字】:創建通信載體時得到的返回值;
        作用:用來監聽一個端口,當有客戶端過來時,給他指路
        【連接套接字】:等待客戶端連接完成後得到的返回值;
        作用:作爲和客戶端(遠程計算機)真正聯繫的【鏈接】
        
        監聽套接字就是個牽線指路的,你實質上是跟它指的那個人說話。
        因爲你要找的那個人不可能隨時等你來,而監聽套接字就是專職等你來問,
        它回答你要找的人在哪,並喚醒你要找的人,於是通話就建立起來了,
        就像現實生活中的接線員一樣。
                    
1.創建監聽套接字    使用socket()函數
    原型:int socket(int domain, int type, int protocol);
    即:socket(協議族,通信類型,具體的協議);
    功能:
            主要用於創建可以實現通信的交流點,也就是socket通信載體(相當於電話機)
    得到監聽套接字        
    返回值:
            成功:返回新的socket描述符【監聽套接字】
            失敗:返回-1,errno被設置            
    例如:
            int sockfd = socket(AF_INET,SOCK_DGRAM,0);
        AF_INET:域/協議族,決定了是【本地通信還是網絡通信】
                    AF_UNIX/AF_LOCAL    用於實現本地通信
                    AF_INET                用於實現基於IPv4的網絡通信
                    AF_INET6            用於實現基於IPv6的網絡通信
        SOCK_DGRAM:通信類型,決定了【具體的通信式】
                    SOCK_STREAM        提供有序的、可靠的、雙向的、面向連接的字節流通信方式,默認使用TCP協議
                    SOCK_DGRAM        提供無序的、不可靠的,非面向連接的數據報通信方式,默認使用UDP協議
        0:指定具體的協議,默認爲0,使用默認協議
                        
2.準備通信地址【要先清零再賦值】                        
通信地址數據【類型】:
1】.通用地址結構
struct sockaddr
{
    sa_family_t sa_family;    //域/協議族
    char sa_data[14];        //??????
};

        2】.IPv4通信地址結構
        struct sockaddr_in
        {
            sa_family_t sin_family;//協議族,AF_INET
            in_port_t sin_port;//16位的端口號
            struct in_addr sin_addr;//IP地址 
        };
        struct in_addr
        {
            in_addr_t s_addr;    //16位的端口號
        };        
    例如:(IPv4通信地址結構)
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[2]));
    saddr.sin_addr.s_addr = inet_addr(argv[1]);
    
【作用】:(以IPv4通信地址結構爲例)                        
        saddr.sin_family:決定該地址遵循何種協議                
        saddr.sin_port:決定該地址的端口    【哪臺機子】                
        saddr.sin_addr.s_addr:決定該地址的IP地址    【哪個網吧】                
【IP地址格式轉換】:
        IP地址從main()函數【輸入時是字符串】格式的,
        初始化通信地址的時候要用inet_addr()函數轉換成結構體類型;
        接收【調用】別人的IP地址時,得到的是【結構體類型】的;
        若要【輸出】,則要用inet_ntoa()函數轉換成【字符串】格式;
        
【端口號格式轉換】:
        端口號從main()函數【輸入時是字符串】格式的,
        初始化通信地址的時候要先用atoi()函數轉換成int型;
        是主機字節順序,要再用 htons()函數轉換成網絡字節順序(大端模式);
        接收【調用】別人的IP地址時,得到的是【網絡字節順序】;                                                                            
        若要【輸出】,則要用ntohs()函數轉換成【主機字節順序】;                                                                            
    端口格式轉換相關【函數詳解】:
            #include <arpa/inet.h>

           uint32_t htonl(uint32_t hostlong);

           uint16_t htons(uint16_t hostshort);

           uint32_t ntohl(uint32_t netlong);

           uint16_t ntohs(uint16_t netshort);

        h:host 本地格式
        n:network    網絡格式(大端模式)
        s:short        2字節整數
        l:long        4字節整數    
        功能:把本地格式轉成網絡格式,或者反過來。
        
        IP地址格式轉換相關函數:
            in_addr_t inet_addr(const char *cp);
            功能:將字符串形式的IP地址轉爲整數類型
            char *inet_ntoa(struct in_addr in);
            功能:將結構類型的IP地址轉爲字符串形式
    
/*************服務器**************/    
3.綁定(通信地址與監聽套接字)        bind()函數                    
        原型:int bind(int sockfd, const struct sockaddr *saddr,
                    socklen_t addrlen);                
        即:bind(監聽套接字描述符,強轉後的通信地址,通信地址大小)    ;            
        功能:
                主要用於綁定socket和具體的通信地址                
        返回值:
                成功:返回0
                失敗:返回-1,errno被設置                
        例如:                
    int ret = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(ret < 0)        //很有必要!!
    {
        perror("bind");
        exit(-1);
    }            
        sockfd:socket描述符,即監聽套接字                
        (struct sockaddr*)&saddr:結構體指針,
        不管是什麼協議的地址結構,都需要強轉爲該類型                
        sizeof(saddr):通信地址結構的大小,使用sizeof()計算即可                
                        
4.監聽        使用listen()函數
        原型:int listen(int sockfd, int backlog);
        即:listen(監聽套接字,監聽隊列大小);
        功能:
                爲套接字sockfd建立一個連接請求監聽隊列,在調用listen函數成功後,這個套接字便成爲服務套接字,即被動套接字        
        返回值:
                成功:返回0
                失敗:返回-1,errno被設置
        例如:        
                listen(sockfd,10);
        sockfd:socket描述符,即監聽套接字                                
        10:監聽隊列的大小                            

5.等待連接    accept()函數
        原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
        即:accept(監聽套接字,強轉後的通信地址,指針類型的通信地址大小);                                
        功能:
                用於接收服務套接字sockfd上的連接請求                
        返回值:
                成功:返回一個【連接套接字】
                (新的,在後面的代碼中起作用,代替監聽套接字出現)
                失敗返回-1,errno被設置                        
        例如:                                
                socklen_t len = sizeof(caddr);        //不能直接在等待中用sizeof(caddr)
                //保存客戶地址的結構體的大小,必需由調用者初始化    
                int confd = accept(sockfd,(struct sockaddr*)&caddr,&len);    
                caddr:    結構體指針,用於保存接受的客戶端通信地址,
                            與被初始化的通信地址一起定義,用來存儲客戶端的地址
                sockfd:socket函數的返回值,監聽套接字
                (struct sockaddr*)&caddr:結構體指針,
                    不管是什麼協議的地址結構,都需要強轉爲該類型                                        
                &len:指針類型,用於保存客戶端網絡地址的信息的長度                            
        注:如果對客戶地址不感興趣,那麼第二、三兩個參數寫NULL即可。
                如果需要客戶的地址,那麼第三個參數必須由調用者初始化。
                
6.通信    
【方法】:把連接套接字當成文件描述符操作,
可以讀取裏面的東西,也可以往裏面寫東西            

7.關閉連接套接字和監聽套接字
            close(confd);
            close(sockfd);                            
/*********************服務器*************/    

/*****************客戶端*************/    
3.連接        使用connect()函數
        原型:int connect(int sockfd, const struct sockaddr *addr,
                   socklen_t addrlen);                                        
        即:connect(監聽套接字描述符,服務器的通信地址,通信地址結構的大小);                                        
        功能:
                用於連接服務器                                    
        返回值:
                成功:返回0
                失敗:返回-1,errno被設置                                            
        例如:
            int ret = connect(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
            if(ret < 0)
            {
                perror("connect");
                exit(-1);
            }        

4.通信    
【方法】:把監聽套接字當成文件描述符操作,
可以讀取裏面的東西,也可以往裏面寫東西    

5.關閉監聽套接字
            close(sockfd);    
/****************客戶端*************/                            
                        
迭代服務器

併發服務器
多進程服務器
多線程服務器
多路複用服務器
                        
【2】.IO多路複用服務器                        

【作用】:實現多個文件的查詢是否就緒,
在某個文件可讀的情況下,馬上讀到數據,                        
【方法】:運用select()函數                        
【原理】:對集合中的文件進行輪詢,每隔一段時間就會去
            詢問文件描述符[0,nfds)中的每一個文件,查看是否就緒,
            如果就緒那麼把相應的文件描述符集合中置1.    .......
        直到有文件就緒或超時或出錯。
    
    超時時間結構體:
        struct timeval {
               time_t         tv_sec;     /* 秒 */
               suseconds_t    tv_usec;    /* 毫秒 */
           };    
    例如:
            struct timeval tv;//超時時間結構體
           /* 超時時間設爲5秒. */
            tv.tv_sec = 5;
            tv.tv_usec = 0;
            
select()【函數原型】:
                    int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);
    即:select(感興趣的文件集合中最大的文件描述符,
                    對讀感興趣的文件描述符集合,
                    對寫感興趣的文件描述符集合,
                    對異常感興趣的文件描述符集合,
                    超時時間);                
    返回值:
        1.有文件數據就緒,立馬返回,返回就緒的文件描述符個數  >0 
        2.超時返回,返回0
        3.出錯了,返回-1 ,errno被設置                
    例如:    
            int retval;
            retval = select(10, &tmpfds, NULL, NULL, &tv);                        
            if(retavl < 0)
            {    //出錯
                perror("select");                
            }            
            else if(retavl > 0)
            {    //有文件就緒
                。。。。        
            }            
            else if(retval == 0)
            {    //等待超時
                。。。。
            }            
    【輔助函數】:
1】.        void FD_ZERO(fd_set *set);            
        功能:初始化指定的集合,全部清零
        例如:
            FD_ZERO(sockfd,&rfds);                                
2】.        void FD_SET(int fd, fd_set *set);    
        功能:把指定的fd設置到集合中去
        例如:
            FD_SET(sockfd,&rfds);                            
3】.        int  FD_ISSET(int fd, fd_set *set);    
        功能:判斷指定的fd是否在這個集合中
        返回值:
                成功:返回非0
                失敗:返回0
        例如:
            FD_ISSET(sockfd,&rfds);                
4】.        void FD_CLR(int fd, fd_set *set);    
        功能:把指定fd從集合中移除
        例如:
            FD_CLR(sockfd,&rfds);
                                        
                                            
    select使用【步驟】:                    
    1.設置文件描述符                
        fd_set rfds,tmpfds;//創建兩個文件描述符集合
        struct timeval tv;//定義一個超時時間結構體                
        int retval;        //定義一個描述符作爲輪詢函數的返回值,
        //用於劃分輪詢結果以便分配任務    
    2.    初始化指定的文件集合,全部清零    
        FD_ZERO(&rfds);//把文件描述符集合清零,即初始化
    3.    把指定的文件的文件描述符設置到集合中去    
        FD_SET(i, &rfds);//把文件描述符i,放到集合rfds中,即把對應的位置1    
    4.初始化時間結構體    ,
        /* 超時時間設爲5秒. */
        tv.tv_sec = 5;
        tv.tv_usec = 0;        
    5.備份需要輪詢的文件描述符集合
        tmpfds = rfds;//拷貝準備好的描述符集合,
        //每循環一次,備份一次文件描述符,啓動一次輪詢函數    
        //防止源集合被覆蓋                    
    6.啓動輪詢函數                    
        retval = select(fd_max+1,&tmpfds,NULL,NULL,&tv);    
    7.判斷指定的fd是否在這個集合中
        FD_ISSET(i,&rfds)    //判斷指定的文件是否在集合中                                                
    8.    把指定fd從集合中移除                                        
        FD_CLR(i,&rfds);//從集合中移除這個連接套接字描述符                        
    9.    關閉文件
        close(i);


【TCP與UDP協議的比較】:
    1.tcp協議:
        傳輸控制協議  類似打電話
        面向連接的    (建立連接-->進行通信-->斷開連接)
        在通信的整個過程中必需保持連接
        該協議保證了數據的傳遞是可靠且有序的
        屬於全雙工的字節流通信方式
        服務器壓力較大,資源消耗大,執行效率較低
        
    2.udp協議:
        用戶數據報協議
        面向非連接的    類似發短信
        在通信的整個過程中不需要保持連接
        不保證數據的可靠性和有序性
        屬於全雙工的數據報通信方式
        服務器壓力較小,資源消耗小,執行效率高
                                                                                                    
【3】.基於【UDP協議】的通信模型                                                            
【注意】:
        1.UDP不分服務器和客戶端
        2.    UDP調用接收函數必須要綁定地址,
        要用socklen_t len = sizeof(saddr);
        求出目標地址長度,在函數中用&len代表長度        
        3.調用方式函數不用綁定地址,也不要先求出長度
        
用法:                                                                        
    1.創建監聽套接字                                                                    
        使用socket()函數                                                                         
    2.準備通信地址
        定義並初始化結構體變量    
/******************接收方**************/
    3.綁定監聽套接字和通信地址
        使用bind()函數                            
    4.通信                                    
————————————————————————————
                                                                            
接收數據報函數:recvfrom()                                                                                
原型:ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                     struct sockaddr *src_addr, socklen_t *addrlen);        
即:recvfrom(監聽套接字描述符,強轉的被髮送的數據首地址,
                發送數據的大小,發送標誌,
                發送數據的目標地址,目標地址的大小);
作用:
        將目標地址發過來的N個字節存到緩衝區中
例如:
        socklen_t len = sizeof(saddr);
        ret = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&saddr,&len);
sockfd:        socket函數的返回值,監聽套接字                                                                        
buf:                被髮送的數據首地址                                                                    
sizeof(buf):    發送數據的大小                                                                        
0:                發送標誌
    0:功能與write一樣,即阻塞
    MSG_DONTWAIT:        非阻塞                                                                        
(struct sockaddr *)&saddr:發送數據的目標地址                                                                
&len:目標地址的大小

**********************************/    
/***************發送方*************/
3.通信                                    
————————————————————————————
發送數據報函數:sendto()
原型:ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);
即:sendto(監聽套接字描述符,強轉的被髮送的數據首地址,
                發送數據的大小,發送標誌,
                發送數據的目標地址,目標地址的大小);
作用:
        將準備好的數據中的N個發送給大小爲M的目標地址,進行通信
例如:
        int res = sendto(sockfd,str,strlen(str),0,
        (struct sockaddr *)&saddr,sizeof(saddr));
sockfd:        socket函數的返回值,監聽套接字                                                                        
str:                被髮送的數據首地址                                                                    
strlen(str):    發送數據的大小                                                                        
0:                發送標誌
    0:功能與write一樣,即阻塞
    MSG_DONTWAIT:        非阻塞                                                                        
(struct sockaddr *)&saddr:發送數據的目標地址    【發給誰】                                                            
sizeof(saddr):目標地址的大小                                                                        
                                                                            
    
**********************************/
5.關閉套接字
    close(sockfd);

【UDP】應用
            廣播        組播        
發送方:1.要有一個套接字
            2.要有一個目標地址(不是給自己用的,所以不用綁定)
            3.要用專門的函數sendto()發送數據報
接收方:1.要有一個套接字
            2.要有一個給自己用的通信地址(需要綁定)和
            一個存儲發送者資料的地址
            3.
            方法一:
            使用setsockopt()函數將默認接收的緩衝區設計爲一個小的緩衝區,
            緩衝區地址和大小任意定義,使用getsockopt()函數得到套接字選項值
            例如:
                setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,(void*)&j,sizeof(j));
                getsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,(void*)&i,&size);
            方法二:
            定義一個多播組結構體變量,並初始化,使用setsockopt()函數將默認接收
            的緩衝區設計爲一個小的緩衝區,緩衝區地址爲定義結構體變量的首地址,
            大小爲結構體變量所佔字節數
            例如://加入多播組的方式
            struct ip_mreq join_addr;
            memset(&join_addr,0,sizeof(join_addr));
            join_addr.imr_multiaddr.s_addr = inet_addr(argv[1]);// 組播組的IP地址。
            join_addr.imr_interface.s_addr = htonl(INADDR_ANY); // 本地某一網絡設備接口的IP地址。        
            setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,(void*)&join_addr,sizeof(join_addr));

            4.綁定監聽套接字和通信地址
            5.使用專門的函數recvfrom()接收數據報
            
            http://blog.csdn.net/chary8088/article/details/2486377
【套接字】:
【概念】:通信的兩方的一種約定,用套接字中的相關函數來完成通信過程
            
【套接字選項】:
【概念】:每個【套接字】在不同的協議層次上【有】不同的【行爲屬性】,
            那麼這個【行爲屬性】就稱爲套接字選項
【作用】:    設置地址複用
                允許發送廣播消息
                將主機加入多播組
                設置發送與接收緩衝區的大小等                        
                                
    我們正常使用套接字編程時,一般只關注數據通信,而忽略套接字的不同特性
    但有時需要設置地址複用,允許發送廣播消息,將主機加入多播組,設置發送與接收緩衝區的大小等
    這些都需要對套接字選項進行設置。    
        
【所用函數】:            
    原型:int getsockopt(int sockfd, int level, int optname,
                      void *optval, socklen_t *optlen);
    即:getsockopt(監聽套接字,套接字選項所在的協議層次,
                            套接字選項的名稱,緩衝區首地址,
                            緩衝區的長度);
    功能:    得到套接字選項值                    
    返回值:
            成功:返回0。
            失敗:返回-1,errno被設置
    例如:

    原型:int setsockopt(int sockfd, int level, int optname,
                      const void *optval, socklen_t optlen);
    即:setsockopt(監聽套接字,套接字選項所在的協議層次,
                            套接字選項的名稱,緩衝區首地址,
                            緩衝區的長度);
    功能:如果認爲套接口的默認發送以及接收緩衝區的尺寸太大時,
    作爲程序設計者的我們可以【將默認發送的緩衝區設計爲一個小的緩衝區】。

    
將socket加入一個組播組,因爲socket要接收組播地址224.0.0.1的
數據,它就必須加入該組播組。結構體struct ip_mreq mreq是
該操作的參數,下面是其定義:
    struct ip_mreq
    {
        struct in_addr imr_multiaddr;   // 組播組的IP地址。
        struct in_addr imr_interface;   // 本地某一網絡設備接口的IP地址。
    };
    一臺主機上可能有多塊網卡,接入多個不同的子網,
    imr_interface參數就是指定一個特定的設備接口,
    告訴協議棧只想在這個設備所在的子網中加入某個組播組。
    有了這兩個參數,協議棧就能知道:在哪個網絡設備接口上
    加入哪個組播組。爲了簡單起見,我們的程序中直接寫明瞭
    IP地址:在172.16.48.2所在的設備接口上加入組播組224.0.1.1。
    這個操作是在網絡層上的一個選項,所以級別是SOL_IP
    IP_ADD_MEMBERSHIP選項把用戶傳入的參數拷貝成了
    struct ip_mreqn結構體:


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章