Tuesday, January 25, 2011

Linux下的網絡編程2

轉:http://cyuyanbiancheng.blog.hexun.com.tw/56835407_d.html
c語言學習:Linux下的網絡編程(二)
網絡編程(3)

3. 
Server和Client的信息函數
  這一章我們來學習轉換和網絡方面的信息函數.

3.1 字節轉換函數
  在網絡上面有著許多類型的機器,這些機器在表示數據的字節順序是不同的比如i386 片是低字節在內存地址的低端,高字節在高端,alpha芯片卻相反為了統一起來,Linux下面,有專門的字節轉換函數.

   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)

在這四個轉換函數中,
        h 代表host, 
        n 代表 network.
        s 代表short 
        l 代表long 

第一個函 數的意義是將本機器上的long數據轉化為網絡上的long. 其他幾個函數的意義也差不多
.. 


3.2 IP和域名的轉換


  在網絡上標誌一臺機器可以用IP或者是用域名.那麽我們怎麽去進行轉換呢?

    struct hostent *gethostbyname(const char *hostname)
    struct hostent *gethostbyaddr(const char *addr,int len,int type)

<netdb.h>;中有struct hostent的定義

    struct hostent{
      char *h_name; /* 
主機的正式名稱 */
      char *h_aliases; /* 
主機的別名 */
      int h_addrtype; /* 
主機的地址類型 AF_INET*/
      int h_length; /* 
主機的地址長度 對於IP4 4字節32*/
      char **h_addr_list; /* 
主機的IP地址列表 */
   };

#define h_addr h_addr_list[0] /* 
主機的第一個IP地址*/

    gethostbyname(): 可以將機器名( linux.yessun.com)轉換為一個結構指針.在這個結構裏 面儲存了域名的信息

    gethostbyaddr(): 可以將一個32位的IP地址(C0A80001)轉換為結構指針. 這兩個函數失敗時返回NULL 且設置h_errno錯誤變量,調用h_strerror()可以得到詳細的 出錯信息


3.3 字符串的IP32位的IP轉換.
  
在網絡上面我們用的IP都是數字加點(192.168.0.1)構成的而在struct in_addr結構中 用的是32位的IP, 我們上面那個32IP(C0A80001)是的192.168.0.1 為了轉換我們可以 使用下面兩個函數

   int inet_aton(const char *cp,struct in_addr *inp)
   char *inet_ntoa(struct in_addr in)
 

函數裏面 a 代表 ascii, n 代表network. 第一個函數表示將a.b.c.dIP轉換為32位的IP,存儲在 inp指針裏面.第二個是將32IP轉換為a.b.c.d的格式.


3.4 服務信息函數  
  在網絡程序裏面我們有時候需要知道端口.IP和服務信息.這個時候我們可以使用以下幾 個函數

    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; /* 
正式服務名 */
        char **s_aliases; /* 別名列表 */         int s_port; /* 端口號 */         char *s_proto; /* 使用的協議 */       };
   

一般我們很少用這幾個函數.對應Client,當我們要得到連接的端口號時在connect調用成 功後使用可得到 系統分配的端口號.對於Server,我們用INADDR_ANY填充後,為了得到連 接的IP我們可以在accept調用成功後 使用而得到IP地址. 在網絡上有許多的默認端口和服務,比如端口21ftp80對應WWW.為了得到指定的端口號 的服務 我們可以調用第四個函數,相反為了得到端口號可以調用第三個函數.
   

3.5 
一個例子

#include <netdb.h>;
#include <stdio.h>;
#include <stdlib.h>;
#include <sys/socket.h>;
#include <netinet/in.h>;
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++) {    /* 這裏我們假設是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)));    }
}


在這個例子裏面,為了判斷用戶輸入的是IP還是域名我們調用了兩個函數,第一次我們假 設輸入的是IP所以調用inet_aton, 失敗的時候,再調用gethostbyname而得到信息

No comments:

Post a Comment