Linux網(wǎng)絡(luò)編程--3. 服務(wù)器和客戶機(jī)的信息函數(shù)
發(fā)布時(shí)間:2008-09-17 閱讀數(shù): 次 來(lái)源:網(wǎng)樂(lè)原科技
這一章我們來(lái)學(xué)習(xí)轉(zhuǎn)換和網(wǎng)絡(luò)方面的信息函數(shù).
3.1 字節(jié)轉(zhuǎn)換函數(shù)
在網(wǎng)絡(luò)上面有著許多類型的機(jī)器,這些機(jī)器在表示數(shù)據(jù)的字節(jié)順序是不同的, 比如i386芯片是低字節(jié)在內(nèi)存地址的低端,高字節(jié)在高端,而alpha芯片卻相反. 為了統(tǒng)一起來(lái),在Linux下面,有專門(mén)的字節(jié)轉(zhuǎn)換函數(shù).
unsigned long int htonl(unsigned long int hostlong)
unsigned short int htons(unisgned short int hostshort)
unsigned long int ntohl(unsigned long int netlong)
unsigned short int ntohs(unsigned short int netshort)
在這四個(gè)轉(zhuǎn)換函數(shù)中,h 代表host, n 代表 network.s 代表short l 代表long 第一個(gè)函數(shù)的意義是將本機(jī)器上的long數(shù)據(jù)轉(zhuǎn)化為網(wǎng)絡(luò)上的long. 其他幾個(gè)函數(shù)的意義也差不多.
3.2 IP和域名的轉(zhuǎn)換
在網(wǎng)絡(luò)上標(biāo)志一臺(tái)機(jī)器可以用IP或者是用域名.那么我們?cè)趺慈ミM(jìn)行轉(zhuǎn)換呢?
struct hostent *gethostbyname(const char *hostname)
struct hostent *gethostbyaddr(const char *addr,int len,int type)
在中有struct hostent的定義
struct hostent{
char *h_name; /* 主機(jī)的正式名稱 */
char *h_aliases; /* 主機(jī)的別名 */
int h_addrtype; /* 主機(jī)的地址類型 AF_INET*/
int h_length; /* 主機(jī)的地址長(zhǎng)度 對(duì)于IP4 是4字節(jié)32位*/
char **h_addr_list; /* 主機(jī)的IP地址列表 */
}
#define h_addr h_addr_list[0] /* 主機(jī)的第一個(gè)IP地址*/
gethostbyname可以將機(jī)器名(如 linux.yessun.com)轉(zhuǎn)換為一個(gè)結(jié)構(gòu)指針.在這個(gè)結(jié)構(gòu)里面儲(chǔ)存了域名的信息
gethostbyaddr可以將一個(gè)32位的IP地址(C0A80001)轉(zhuǎn)換為結(jié)構(gòu)指針.
這兩個(gè)函數(shù)失敗時(shí)返回NULL 且設(shè)置h_errno錯(cuò)誤變量,調(diào)用h_strerror()可以得到詳細(xì)的出錯(cuò)信息
3.3 字符串的IP和32位的IP轉(zhuǎn)換.
在網(wǎng)絡(luò)上面我們用的IP都是數(shù)字加點(diǎn)(192.168.0.1)構(gòu)成的, 而在struct in_addr結(jié)構(gòu)中用的是32位的IP, 我們上面那個(gè)32位IP(C0A80001)是的192.168.0.1 為了轉(zhuǎn)換我們可以使用下面兩個(gè)函數(shù)
int inet_aton(const char *cp,struct in_addr *inp)
char *inet_ntoa(struct in_addr in)
函數(shù)里面 a 代表 ascii n 代表network.第一個(gè)函數(shù)表示將a.b.c.d的IP轉(zhuǎn)換為32位的IP,存儲(chǔ)在 inp指針里面.第二個(gè)是將32位IP轉(zhuǎn)換為a.b.c.d的格式.
3.4 服務(wù)信息函數(shù)
在網(wǎng)絡(luò)程序里面我們有時(shí)候需要知道端口.IP和服務(wù)信息.這個(gè)時(shí)候我們可以使用以下幾個(gè)函數(shù)
int getsockname(int sockfd,struct sockaddr *localaddr,int *addrlen)
int getpeername(int sockfd,struct sockaddr *peeraddr, int *addrlen)
struct servent *getservbyname(const char *servname,const char *protoname)
struct servent *getservbyport(int port,const char *protoname)
struct servent
{
char *s_name; /* 正式服務(wù)名 */
char **s_aliases; /* 別名列表 */
int s_port; /* 端口號(hào) */
char *s_proto; /* 使用的協(xié)議 */
}
一般我們很少用這幾個(gè)函數(shù).對(duì)應(yīng)客戶端,當(dāng)我們要得到連接的端口號(hào)時(shí)在connect調(diào)用成功后使用可得到 系統(tǒng)分配的端口號(hào).對(duì)于服務(wù)端,我們用INADDR_ANY填充后,為了得到連接的IP我們可以在accept調(diào)用成功后 使用而得到IP地址.
在網(wǎng)絡(luò)上有許多的默認(rèn)端口和服務(wù),比如端口21對(duì)ftp80對(duì)應(yīng)WWW.為了得到指定的端口號(hào)的服務(wù) 我們可以調(diào)用第四個(gè)函數(shù),相反為了得到端口號(hào)可以調(diào)用第三個(gè)函數(shù).
3.5 一個(gè)例子
#include
#include
#include
#include
#include
int main(int argc ,char **argv)
{
struct sockaddr_in addr;
struct hostent *host;
char **alias;
if(argc<2)
{
fprintf(stderr,"Usage:%s hostname|ip..\n\a",argv[0]);
exit(1);
}
argv++;
for(;*argv!=NULL;argv++)
{
/* 這里我們假設(shè)是IP*/
if(inet_aton(*argv,&addr.sin_addr)!=0)
{
host=gethostbyaddr((char *)&addr.sin_addr,4,AF_INET);
printf("Address information of Ip %s\n",*argv);
}
else
{
/* 失敗,難道是域名?*/
host=gethostbyname(*argv); printf("Address information
of host %s\n",*argv);
}
if(host==NULL)
{
/* 都不是 ,算了不找了*/
fprintf(stderr,"No address information of %s\n",*argv);
continue;
}
printf("Official host name %s\n",host->h_name);
printf("Name aliases:");
for(alias=host->h_aliases;*alias!=NULL;alias++)
printf("%s ,",*alias);
printf("\nIp address:");
for(alias=host->h_addr_list;*alias!=NULL;alias++)
printf("%s ,",inet_ntoa(*(struct in_addr *)(*alias)));
}
}
在這個(gè)例子里面,為了判斷用戶輸入的是IP還是域名我們調(diào)用了兩個(gè)函數(shù),第一次我們假設(shè)輸入的是IP所以調(diào)用inet_aton, 失敗的時(shí)候,再調(diào)用gethostbyname而得到信息.