一、套接字
在網絡中用來描述計算機中不同程序與其他計算機程序通信的方式。爲了區分不同應用程序的進程和連接,需要使用應用程序與TCP/IP協議交互的套接字端口。
主要用到三個參數:通信的目的IP地址、使用的傳輸協議(TCP或UDP)和使用的端口號。
1.套接字相關的數據類型
套接字編程是,通常使用sockaddr和sockaddr_in這兩個系統中定義的數據類型結構體。
struct sockaddr
{
unsigned short int sa_family; //指定通信的地址類型,如果是TCP/IP通信,則爲AF_INET。
char sa_data[14]; //最多使用14個字符長度,用來保存ip地址和端口信息。
}
sockaddr_in的功能和sockaddr相同,不同的是ip地址和端口分開爲不同的成員。
struct sockaddr_in
{
unsigned short in sin_family; //和sa_family相同
uint16_t sin_port; //端口號
struct in_addr sin_addr; //ip地址
unsigned char sin_zero[8]; //未使用字段
}
in_addr也是個結構體,作用是用來保存ip地址。
struct in_addr
{
uint32_t s_addr;//四個字節的ip地址
}
2.套接字類型
套接字類型指的是在網絡通信中不同的數據傳輸方式:
- 流套接字(SOCK_STREAM):使用面向連接的可靠的數據通信方式,即TCP(Transmission Control Protocol)協議。
- 數據報套接字(Raw Sockets):使用不面向連接的數據通信方式,即UDP(User Datagram Protocol)協議。
- 原始套接字(SOCK_RAW):前面講述的兩種套接字是系統定義的,所有的信息頭需要按照這種方式進行封裝。原始套接字是沒有經過處理的ip數據報,可以根據自己的程序的要求進行封裝。如果要訪問其他協議,則需要使用原始套接字來構造相應協議。
二、域名與ip地址
1. 使用域名獲得主機的ip地址
使用域名獲得主機的ip地址函數是:gethostbyname();返回一個主機地址結構體。
struct hostent *gethostbyname(const char *name);
hostent主機地址結構體:
struct hostent
{
char *h_name; //Official name of host.
char **h_aliases; // Alias list.
int h_addrtype; // Host address type.
int h_length; // Length of address.
char **h_addr_list; // List of addresses from name server.
}
實例:
#include<stdio.h>
#include<sys/socket.h>
#include<netdb.h>
#include<string.h>
#include<arpa/inet.h>
int main(){
extern int h_errno; //捕捉網絡錯誤
struct hostent *host;
char hostname[] = "www.163.com";
char hostname2[] = "www.sjaife.com"; //不存在的域名
struct in_addr in;
memset(&in,0,sizeof(in));
if((host = gethostbyname(hostname)) != NULL){
memcpy(&in.s_addr,host->h_addr_list,4); //將地址複製給結構體
printf("Domain name:%s \n",host->h_name);
printf("IP length : %d \n",host->h_length);
printf("Type : %d\n",host->h_addrtype);
printf("IP : %s \n",inet_ntoa(in)); //將十進制地址轉換爲網絡ip地址
}else{
printf("Domain name: %s \n",hostname);
printf("error: %d\n",h_errno);
printf("%s\n",hstrerror(h_errno)); //hstrerror函數將錯誤號轉換爲提示的錯誤字符串
}
printf("-------------------------------\n");
if((host = gethostbyname(hostname2)) != NULL){
memcpy(&in.s_addr,host->h_addr_list,4);
printf("Domain name:%s \n",host->h_name);
printf("IP length : %d \n",host->h_length);
printf("Type : %d\n",host->h_addrtype);
printf("IP : %s \n",inet_ntoa(in));
}else{
printf("Domain name: %s \n",hostname2);
printf("error: %d\n",h_errno);
printf("%s\n",strerror(h_errno));
}
return 0;
}
/*
輸出結果
Domain name:www.163.com
IP length : 4
Type : 2
IP : 228.154.106.0
-------------------------------
Domain name: www.sjaife.com
error: 1
Operation not permitted
*/
2.用IP地址返回域名
用IP地址可以查詢到這個iP對於的域名,需要使用的是gethostbyaddr()函數;
struct hostent *gethostbyaddr(const void *addr,socklet_t,int type);
addr:保存了ip地址的字符串
socklen_t:ip地址的長度
type:一般值爲AF_INET
實例:
#include<stdio.h>
#include<sys/socket.h>
#include<netdb.h>
#include<string.h>
#include<arpa/inet.h>
int main(){
struct hostent *host;
extern int h_errno;
struct in_addr in;
char addr[] = "183.220.192.136";
if((host = gethostbyaddr(addr,sizeof(addr),AF_INET)) != NULL){
memcpy(&in,host->h_addr_list,4);
printf("Domain name: %s \n",host->h_name);
printf("IP length : %d\n",host->h_length);
printf("Type: %d\n",host->h_addrtype);
printf("IP : %s\n",inet_ntoa(in));
}else{
printf("IP: %s\n",addr);
printf("errno: %d\n",h_errno);
printf("%s\n",hstrerror(h_errno));
}
return 0 ;
}
三、網絡IP地址的轉換
網絡IP地址在網絡傳輸與計算機內部的自己存儲方式是不同的,需要用相關函數對網絡IP地址進行轉換。
1.將網絡地址轉換成長整型數
函數inet_addr()可以將網絡IP地址轉換爲十進制的長整型數:
long inet_addr(char *cp);
實例:
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main(){
char cp[] = "192.168.1.1";
printf("ld\n",inet_addr(cp));
}
輸出結果爲:16885952
2.將長整型IP地址轉換爲網絡地址
inet_ntoa()可以將一個IP類型的結構體轉換成點分十進制的網絡IP地址。
char *inet_ntoa(struct in_addr in);
實例:
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main(){
struct in_addr in;
in.s_addr = 16885952;
printf("%s\n",inet_ntoa(in));
}
輸出結果:192.168.1.1
四、錯誤處理
在網絡程序中,可以使用下面的語句來捕獲發生錯誤的編號。
extern int h_error;
捕獲這個錯誤編號後,可以用hstrerror()函數輸出這個錯誤信息:
char *hstrerror(int err);
實例:
#include<stdio.h>
#include<netdb.h>
int main(){
int i;
for(i = 0 ; i < 10 ; i++){
printf("%d : %s \n",i,hstrerror(i));
}
}
輸出結果:
0 : Resolver Error 0 (no error)
1 : Unknown host
2 : Host name lookup failure
3 : Unknown server error
4 : No address associated with name
5 : Unknown resolver error