1. 程式人生 > >Socket學習筆記之二(常用基本函式)

Socket學習筆記之二(常用基本函式)

函式:
u_long htonl(u_long hostlong)
u_short htons(u_short hostshort)
u_long ntohl(u_long netlong)
u_short ntohs(u_short netshort)

這上面四個函式類似,功能相似,都用來轉換資料格式。用來實現處理器中short,long資料型別與網路中的轉換。在網路中傳輸均以位元組為單位(除了bit外就是最小的單位了)。一個short佔兩位元組,一個long佔四個位元組。一個short從一臺機子傳到另外一臺機子上要能夠還原,則必須統一規定高低位元組順序。在TCP/IP協議規範中short的高位在低位元組,低位在高位元組。這與有些處理器中或者系統中表示不一樣。例如在windows中:
 unsigned short hs = 0x0102;
 unsigned short ns = htons( hs );
 printf( "0x%04x",ns);//ns:0x0201
所以對於網路埠等資料在使用前必須進行統一,例如
unsigned short port = 2088;
m_sockaddr.sin_port = htons( port );
等等。這四個函式,我開始不知道為什麼取這些名字總是記不住,後來想明白了
htons表示host to net short,ntohs表示net to host short
htonl表示host to net long,ntohl表示net to host long
這樣不需要刻意去記也就明白了。

unsigned long inet_addr(const char* cp);
char* FAR inet_ntoa(struct in_addr in);

這兩個函式用來把表示ip地址的字串(如:202.114.14.12)跟表示ip的long或者結構之間轉換。
inet_addr得到的是已經統一位元組順序的,可以直接賦值給in_addr裡的s_adr,例如:
 char *pHost = "202.114.14.12"
 m_sockaddr.sin_addr.s_addr = inet_addr( pHost );

int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);


載入winsock庫。返回0表示成功,非0表示錯誤。第一個引數是版本號,現在最高版本是2.2版,不過Win CE好像只支援1.1版,高位位元組表示副版本號,低位位元組表示高版本號,所以這裡一般就是0x0202或者0x0101或者使用巨集定義MAKEWORD(2,2)或者MAKEWORD(1,1),第二個引數是一個與winsock庫資訊有關的結構,一把不用去管它。在使用winsock前,都必須載入,一般在程式初始化時候做這個事情。一般使用如下:
 WSADATA data;
 if ( WSAStartup(0x0202,&data) != 0 )
 {
  printf("error id: %d",GetLastError());
 }
上面的GetLastError()
是使用非常頻繁的函式。很多函式的返回值得意義都是表示函式執行是否出錯。當winsock的函式發生錯誤時,用GetLastError()可以得到最後一次發生錯誤的錯誤號。在.Net中有個工具:查詢錯誤,輸入錯誤號,得到錯誤資訊。

int gethostname(char* name,int namelen);
獲取主機名。輸入引數為緩衝區地址和大小。
struct hostent* FAR gethostbyname(const char* name);
由主機名得到主機資訊,可以用來解析域名。需要注意的是MSDN中的一段話“The application must never attempt to modify this structure or to free any of its components. Furthermore, only one copy of this structure is allocated per thread, so the application should copy any information it needs before issuing any other Windows Sockets function calls”這說明了一般用法的時候,要把資料拷貝出來,看看下面程式碼:
 char   name[255];
 PHOSTENT  phostinfo;
 PHOSTENT  phostinfo1;
 WSADATA data;
 struct in_addr** addrPtr;
 struct in_addr** addrPtr1;

 if ( WSAStartup(0x0202,&data) != 0 )
 {
  printf("error id: %d",GetLastError());
 }

 if( gethostname ( name, sizeof(name)) == 0)
 {
  printf("%s",name);
  if((phostinfo = gethostbyname(name)) != NULL)
  {
   for (addrPtr = (struct in_addr **)phostinfo->h_addr_list;*addrPtr;addrPtr++)
   {//顯示我機子的ip
    printf("%s\n", inet_ntoa(**addrPtr));
   }
  }
  else
   printf("error id : %d",GetLastError());
 }
 else
 {
  printf("error id :%d",GetLastError());
 }

 if((phostinfo1 = gethostbyname("bbs.whnet.edu.cn")) != NULL)
 {
  for (addrPtr1 = (struct in_addr **)phostinfo->h_addr_list;*addrPtr1;addrPtr1++)
  {//顯示bbs.whnet.edu.cn的ip:202.114.0.248
   printf("%s\n", inet_ntoa(**addrPtr1));
  }
 }
 else
  printf("error id : %d",GetLastError());

 for (addrPtr = (struct in_addr **)phostinfo->h_addr_list;*addrPtr;addrPtr++)
 {//在這裡顯示的是bbs.whnet.edu.cn的ip:202.114.0.248,不是我機子的ip
  printf("%s\n", inet_ntoa(**addrPtr));
 }

struct HOSTENT* FAR gethostbyaddr(const char* addr,int len,int type);
根據ip地址得到主機資訊。這裡的ip必須是網路位元組順序的。示例程式碼:
 PHOSTENT phostinfo2;
 unsigned long ip = inet_addr("127.0.0.1");
 if ( (phostinfo2 = gethostbyaddr((char*)&ip,sizeof(ip),AF_INET)) != NULL)
 {//顯示localhost
  printf("host name : %s",phostinfo2->h_name );
 }
 else
  printf("error id : %d",GetLastError());

int getsockname(SOCKET s,struct sockaddr* name,int* namelen);
這個函式用來的得到socket的本地地址,但是前提是socket必須已經bind或者已經是連線上的。如果socket不是面向連線的話,比如udp,那得socket上有資料才行。
int getpeername(SOCKET s,struct sockaddr* name,int* namelen);
這個函式用來得到socket那一邊上的地址,顯然socket必須得連線上。“The getpeername function can be used only on a connected socket. For datagram sockets, only the name of a peer specified in a previous connect call will be returned—any name specified by a previous sendto call will not be returned by getpeername.”

至於bind,listen,accept,recv,send等後面學select模型的時候再仔細研究。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=551760