內(nèi)核技術(shù):TCP/IP編程實現(xiàn)遠程文件傳輸

字號:

TCP/IP編程實現(xiàn)遠程文件傳輸
    在TCP/IP網(wǎng)絡結(jié)構(gòu)中,為了保證網(wǎng)絡安全,網(wǎng)絡人員往往需要在路由器上添加防火墻,禁止非法用戶用ftp等安全危害較大的TCP/IP協(xié)議訪問主機。而有時系統(tǒng)維護人員需要用ftp將一些文件從中心機房主機傳到前端網(wǎng)點主機上,比如應用程序的替換升級。如果每次傳輸文件時都要打開防火墻,未免顯得有些繁瑣,要是在自己的應用程序中增加一個專門的文件傳輸模塊,那將是十分愉快的事情。
    UNIX網(wǎng)絡程序設(shè)計一般都采用套接字(socket)系統(tǒng)調(diào)用。針對目前十分流行的客戶/服務器模式,其程序編寫步驟如下:
    1.Socket系統(tǒng)調(diào)用
    為了進行網(wǎng)絡I/O,服務器和客戶機兩端的UNIX進程要做的第一件事是調(diào)用socket()系統(tǒng)調(diào)用,建立軟插座,指明合適的通訊協(xié)議。格式為:
    #include;
    #include;
    int socket(int family,int type,int protocol)
    其中:(1)family指明套節(jié)字族,其值包括:
    AF_UNIX   (UNIX內(nèi)部協(xié)議族)
    AF_INET   (Iternet協(xié)議)
    AF_NS (XeroxNs協(xié)議,TCP/IP編程取該值)
    AF_IMPLINK  (IMP鏈接層)
    (2)type 指明套接字類型,取值有:
    SOCK_STREAM     (流套接字)
    SOCK_DGRAM     (數(shù)據(jù)報套接字)
    SOCK_RAW      (原始套接字)
    SOCK_SEQPACKET   (定序分組套接字)
    一般情況下,前兩個參數(shù)的組合就可以決定所使用的協(xié)議,這時第三個參數(shù)被置為0,如果第一個參數(shù)為AF_INET,第二個參數(shù)選SOCK_STREAM,則使用的協(xié)議為TCP;第二個參數(shù)選SOCK_DGRAM,則使用的協(xié)議為UDP;當?shù)诙€參數(shù)選SOCK_RAW時,使用的協(xié)議為IP。值得指出的是并不是所有的族和類型的組合都是合法的,具體請查閱相關(guān)資料。該系統(tǒng)調(diào)用若成功則返回一個類似文件描述符,成為套節(jié)字描述字,可以像文件描述符那樣用read和write對其進行I/O操作。當一個進程使用完該軟插座時,需用close(<描述符>關(guān)閉(具體見后面內(nèi)容)。
    2.服務器端Bind系統(tǒng)調(diào)用
    軟插座創(chuàng)建時并沒有與任何地址相關(guān)聯(lián),必須用bind()系統(tǒng)調(diào)用為其建立地址聯(lián)系。其格式為:
    #include;
    #include;
    int bind(int socketfd,struct sockaddr_in *localaddr,sizeof(localaddr));
    其中:(1)第一個參數(shù)socketfd是前步socket()系統(tǒng)調(diào)用返回的套節(jié)字描述符。
    (2)第二個參數(shù)被捆向本地地址的一種結(jié)構(gòu),該結(jié)構(gòu)在sys/netinet/in.h中定義:
    struct sockaddr_in{
    short sin_family;/*socket()系統(tǒng)調(diào)用的協(xié)議族如AF_INET*/
    u_short sin_port;/*網(wǎng)絡字節(jié)次序形式的端口號碼*/
    struct in_addr sin_addr;/*網(wǎng)絡字節(jié)次序形式的網(wǎng)絡地址*/
    char sin_zero[8];
    }
    一臺機器上的每個網(wǎng)絡程序使用一個各自獨立的端口號碼,例如:telnet程序使用端口號23,而ftp文件傳輸程序使用端口號21。我們在設(shè)計應用程序時,端口號碼可以由getservbyname()函數(shù)從/etc/services庫文件中獲取,也可以由htons (int portnum)函數(shù)將任意正整數(shù)轉(zhuǎn)換為網(wǎng)絡字節(jié)次序形式來得到,有些版本的UNIX操作系統(tǒng)則規(guī)定1024以下的端口號碼只可被超級用戶使用,普通用戶程序使用的端口號碼只限于1025到32767之間。網(wǎng)絡地址可以由gethostbyname(char*hostname)函數(shù)得到(該函數(shù)和getservbyname()一樣都以網(wǎng)絡字節(jié)次序形式返回所有在他們結(jié)構(gòu)中的數(shù)據(jù)),參數(shù)hostname為/etc/hosts文件中某一網(wǎng)絡地址所對應的機器名。該函數(shù)返回一個類型為hostent的結(jié)構(gòu)指針,hostent結(jié)構(gòu)在netdb.h中定義:
    struct hostent{
     char *h_name;
     char **h_aliases;
     int h_addrtype;
     int h_length;  /*地址長度*/
     char **h_addr_list;
     #define h_addr h_addr_list[0];/*地址*/
    }
    (3)第三個參數(shù)為第二個結(jié)構(gòu)參數(shù)的長度,如果調(diào)用成功,bind返回0,否則將返回-1并設(shè)置errno。