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。
在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。

