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 

Guess you like

Origin blog.csdn.net/psl1234554321/article/details/104760322