網絡編程相關api

回顧:
    OSI七層模型
    
    應用層
    表示層
    會話層
    傳輸層
    網絡層
    數據鏈路層
    
    物理層
    
    TCP/IP四層模型
    
    IP地址
    A    0 + 7 + 24
    B    10 + 14 + 16
    C    110 + 21 + 8
    D    1110 + 28位組播地址
    E    留待備用
    
    192.168.0.103 /24
    
    127.0.0.1:迴環地址,可用於本機網絡協議的測試和本地進程間通信
    
    端口號
    
    16位無符號整數,0-65535            1024被系統使用
    
    
    字節序
    
---------------------------------
socket編程:
1.網絡編程又叫socket編程
    套接字是一個網絡編程的接口,是網絡數據傳輸的軟設備,用於網絡交互。
    
    網絡編程就是編寫程序使兩臺連網的計算機相互交換數據,這個就是網絡編程的全部內容。
    
    unix/linux系統作爲服務器操作系統存在至今,因此,Linux的網絡功能應該是非常全面和強大。
    
    網絡編程其實有很成熟的通信模型,並且windows也通用。
    
2.通信模型(基於TCP的一對一的通信模型)
    
    服務器:
        1.創建socket,使用函數socket()
        2.準備通信地址,使用結構體類型
        3.綁定socket和通信地址,使用bind()
        4.監聽,使用函數listen()
        5.等待連接,使用函數accept()
        6.進行通信,使用read()、write()
        7.關閉socket,使用函數close()
        
    客戶端:
        1.創建socket,使用函數socket()
        2.準備通信地址(指服務器的地址),使用結構體類型
        3.連接服務器,使用函數connect()
        4.進行通信,使用read()、write()
        5.關閉socket,使用函數close()

具體函數:
    1.socket()函數
        #include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>

        int socket(int domain, int type, int protocol);
        功能:主要用於創建可以實現通信的交流點,也就是socket通信載體(相當於電話機)
        第一個參數:域/協議族,決定了是本地通信還是網絡通信
                    AF_UNIX/AF_LOCAL    用於實現本地通信
                    AF_INET                用於實現基於IPv4的網絡通信
                    AF_INET6            用於實現基於IPv6的網絡通信
                    
        第二個參數:通信類型,決定了具體的通信式
                    SOCK_STREAM        提供有序的、可靠的、雙向的、面向連接的字節流通信方式,默認使用TCP協議
                    SOCK_DGRAM        提供無序的、不可靠的,非面向連接的數據報通信方式,默認使用UDP協議
                    
        第三個參數:指定具體的協議,默認爲0,使用默認協議

        返回值:成功返回新的socket描述符
                失敗返回-1,errno被設置
        
                    
    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;
        };        
        
    例:
        struct sockaddr_in saddr;
        memset(&saddr,0,sizeof(saddr);
        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(10086);
        saddr.sin_addr.s_addr = inet_addr("192.168.0.103");
        
        
        端口格式轉換相關函數:
            #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()
        include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>

        int bind(int sockfd, const struct sockaddr *addr,
                socklen_t addrlen);
        功能:主要用於綁定socket和具體的通信地址
        第一個參數:socket描述符,socket函數的返回值
        第二個參數:結構體指針,不管是什麼協議的地址結構,都需要強轉爲該類型
        第三個參數:通信地址結構的大小,使用sizeof()計算即可
        返回值:成功返回0
                失敗返回-1,errno被設置
                
    4.監聽listen函數
        #include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>

        int listen(int sockfd, int backlog);
        功能:爲套接字sockfd建立一個連接請求監聽隊列,在調用listen函數成功後,這個套接字便成爲服務套接字,即被動套接字        
        第一個參數: socket描述符
        第二個參數:監聽隊列的大小
        返回值:成功返回0
                失敗返回-1,errno被設置
                
    5.等待連接,accept函數
        #include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>

        int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
        功能:用於接收服務套接字sockfd上的連接請求
        第一個參數:socket描述符,socket函數的返回值
        第二個參數:結構體指針,用於保存接受的客戶端通信地址
        第三個參數:指針類型,用於保存客戶端網絡地址的信息的長度
        返回值:成功返回一個連接套接字
                失敗返回-1,errno被設置
        注:如果對客戶地址不感興趣,那麼第二、三兩個參數寫NULL即可。
            如果需要客戶的地址,那麼第三個參數必須由調用者初始化。

        
    6.連接函數connect
        #include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>

        int connect(int sockfd, const struct sockaddr *addr,
                   socklen_t addrlen);
        功能:用於連接服務器
        第一個參數:socket描述符,socket函數的返回值
        第二個參數:服務器的通信地址
        第三個參數:通信地址結構的大小,使用sizeof計算
        返回值:成功返回0
                失敗返回-1,errno被設置
        

        
        迭代服務器
        
        併發服務器
            多進程服務器
            多線程服務器
            多路複用服務器
        
        
        
        
    作業:
        用多線程服務器實現羣聊
        
        ./a.out 192.168.0.129 10086 name
        
        [name] hello
        [name] hello
        
        confd用數組保存即可
        當有客戶連接,保存其fd
        當有客戶下線,移除其fd
        
        保存和移除的操作必須同步
    
    
    
-------------------------
IO多路複用
    假如我們要在一個文件可讀的情況下,馬上讀到數據,我們可以在這個文件上阻塞的讀
    如果有多個文件,那麼就需要多個進程/線程去阻塞的讀每個文件
    
    能不能用一個函數,去實現多個文件的查詢是否就緒的功能?
    select()
    
    運用select()函數是最具有代表性的實現複用服務器的方法
    
        #include <sys/select.h>

       /* According to earlier standards */
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);
                  
            參數:    
                    nfds:感興趣的文件集合中最大的文件描述符 + 1;
                    readfds:對讀感興趣的文件描述符集合
                    writefds:對寫感興趣的文件描述符集合
                    exceptfds:對異常感興趣的文件描述符集合
                    timeout:超時時間
                    
        select實現原理:
            select 在實現時,會輪詢,每隔一段時間就會去詢問文件描述符[0,nfds)中的每一個文件,查看是否就緒,如果就緒那麼把相應的文件描述符集合中置1.
            ...
            直到有文件就緒或超時或出錯。

       void FD_CLR(int fd, fd_set *set);    //把指定fd從集合中移除
       int  FD_ISSET(int fd, fd_set *set);    //判斷指定的fd是否在這個集合中
       void FD_SET(int fd, fd_set *set);    //把指定的fd設置到集合中去
       void FD_ZERO(fd_set *set);            //初始化指定的集合,全部清零
       
        struct timeval {
               time_t         tv_sec;     /* seconds */
               suseconds_t    tv_usec;    /* microseconds */
           };

        在調用select函數之前,readfds是你對讀感興趣的文件描述符集合
        在調用select函數之後,readfds是你對讀感興趣並且可以讀的文件描述符集合
        writefds,exceptfds同理。
        
        timeout 在調用select之前,是超時時間
                在調用select之後,是剩餘時間
                
        select返回:
            1.有文件數據就緒,立馬返回,返回就緒的文件描述符個數  >0 
            2.超時返回,返回0
            3.出錯了,返回-1 ,errno被設置
                
        select調用方法與順序:
            1.    設置文件描述符
                指定監控範圍
                設置超時時間
                
            2.調用select函數
            3.查看調用結果
       
       
-----------------------------------------
1.TCP與UDP協議的比較:
    1.tcp協議:
        傳輸控制協議  類似打電話
        面向連接的    (建立連接-->進行通信-->斷開連接)
        在通信的整個過程中必需保持連接
        該協議保證了數據的傳遞是可靠且有序的
        屬於全雙工的字節流通信方式
        服務器壓力較大,資源消耗大,執行效率較低
        
    2.udp協議:
        用戶數據報協議
        面向非連接的    類似發短信
        在通信的整個過程中不需要保持連接
        不保證數據的可靠性和有序性
        屬於全雙工的數據報通信方式
        服務器壓力較小,資源消耗小,執行效率高
        
2.基於UDP協議的通信模型
    服務器:
        1.創建socket,使用socket()函數 
        2.準備通信地址,使用結構體類型
        3.綁定socket和通信地址,使用bind函數
        4.進行通信,使用sendto()/recvfrom()
        5.關閉socket,使用函數close
        
    客戶端:
        1.創建socket,使用socket()函數 
        2.準備通信地址,使用結構體類型
        3.進行通信,使用sendto()/recvfrom()
        4.關閉socket,使用函數close()
        
        
    相關API:
        發送數據報函數:sendto()
        #include <sys/types.h>
        #include <sys/socket.h>

        ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);
        第一個參數:socket描述符,socket函數的返回值
        第二個參數:被髮送的數據首地址
        第三個參數:發送數據的大小
        第四個參數:發送標誌
                    0:功能與write一樣,即阻塞
                    MSG_DONTWAIT:        非阻塞
                    
        第五個參數:發送數據的目標地址
        第六個參數:目標地址的大小
        
        
        接收數據報的函數:recvfrom()            
        ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);
                        
        參數:參考sendto()函數
    
    
-----------------
UDP應用:
    廣播
    組播
    
套接選項:
    我們正常使用套接字編程時,一般只關注數據通信,而忽略套接字的不同特性
    但有時需要設置地址複用,允許發送廣播消息,將主機加入多播組,設置發送與接收緩衝區的大小等
    這些都需要對套接字選項進行設置。
    
    每個套接字在不同的協議層次上有不同的行爲屬性,那麼這個行爲屬性就稱爲套接字選項
    
    getsockopt
    setsockopt
    
        #include <sys/types.h>          /* See NOTES */
        #include <sys/socket.h>

        int getsockopt(int sockfd, int level, int optname,
                      void *optval, socklen_t *optlen);
        注:optlen要初始化
        
        int setsockopt(int sockfd, int level, int optname,
                      const void *optval, socklen_t optlen);
                      
        第一個參數:socket描述符,socket函數的返回值
        第二個參數:要設置的套接字選項所在的協議層次
        第三個參數:套接字選項的名稱
        第四個參數:保存要設置的選項值 的 緩衝區首地址
        第五個參數:第四個參數的長度
        

        SOL_SOCKET    
            SO_BROADCAST        允許發送廣播數據報    int
            SO_REUSEADDR        允許重用本地地址    int 
        
            SO_RCVBUF            接收緩衝區大小        int
            SO_SNDBUF            發送緩衝區大小        int
            
        IPPROTO_IP
            IP_ADD_MEMBERSHIP    加入多播組            ip_mreq{}


廣播:
    廣播是向同一網絡中的所有主機傳輸數據的方法,是基於UDP的
    

    廣播地址:
        192.168.0.255        直接廣播/子網內廣播
        255.255.255.255     本地廣播/全網廣播

多播/組播:
    多播/組播的數據傳輸也是基於UDP的,是同時傳遞到加入特定多播組的大量主機。
    多播組是D類IP地址(224.0.0.0~239.255.255.255)
    
    加入多播組的方式:
        struct ip_mreq
        {
            struct in_addr imr_multiaddr;//多播組的IP
            struct in_addr imr_interface;//加入多播組的那臺主機的IP
        };
        
        struct ip_mreq join_addr;
        join_addr.imr_multiaddr.s_addr = inet_addr("224.1.2.3");
        join_addr.imr_interface.s_addr = inet_addr("192.168.1.110");        
        setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,(void*)&join_addr,sizeof(join_addr));
    

UNIX協議域    unix domain socket
    AF_UNIX/
    AF_LOCAL
        #include <sys/un.h>

        #define UNIX_PATH_MAX    108
        struct sockaddr_un 
        {
           sa_family_t sun_family;               /* AF_UNIX */
           char        sun_path[UNIX_PATH_MAX];  /* pathname */
        };

    利用socket編程接口,來實現本地進程間通信
    UDS提供兩類套接字:
        字節流套接字(類似於TCP)
        數據報套接字(類似於UDP)
        
    練習:
        利用網絡傳輸文件
        1.文件名
        2.文件大小    stat()
        3.文件內容
        
        
    
 

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