linux/unix網絡編程-入門基礎

一、套接字

  在網絡中用來描述計算機中不同程序與其他計算機程序通信的方式。爲了區分不同應用程序的進程和連接,需要使用應用程序與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 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章