Linux网络编程2——系统函数

socket信息数据结构

#include <netinet/in.h>

struct sockaddr
{
    unsigned short sa_family;      /*地址族*/
    char sa_data[14];              /*14字节的协议地址,包含该socket的IP地址和端口号。*/
};
struct sockaddr_in
{
    short int sa_family;           /*地址族*/
    unsigned short int sin_port;   /*端口号*/
    struct in_addr sin_addr;       /*IP地址*/
    unsigned char sin_zero[8];     /*填充0 以保持与struct sockaddr同样大小*/
};
struct in_addr
{
        unsigned long int  s_addr;    /* 32位IPv4地址,网络字节序 */
};
#include <netinet/in.h>

tips
sa_family:
AF_INET   -> IPv4协议
AF_INET6  -> IPv6协议

注意

结构体struct in_addr中存放的s_addr,是无符号整型数。实际上32位IPv4地址为点分十进制,每个字节的范围均为0-255,只要高字节大于等于128,那么这个整型数必然为负数,只不过我们这边仅仅关心ip每一位的存储情况,因此此处可以使用无符号数进行存储。

函数原型1

SYNOPSIS
       #include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>

       int inet_aton(const char *cp, struct in_addr *inp);/* 注意,参数inp为传出参数 */
       char *inet_ntoa(struct in_addr in);
实际上,我们在上篇文章中实现的三个函数是有系统函数可以直接调用的。我们的my_atoh,my_hton合并为系统函数inet_aton,而my_ntoa即为系统函数inet_ntoa。

举例1

/*************************************************************************
    > File Name: test.c
    > Author: KrisChou
    > Mail:[email protected]
    > Created Time: Wed 27 Aug 2014 11:06:11 PM CST
 ************************************************************************/

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    char ip_buf[] = "180.97.33.107";
    struct in_addr my_addr;
    inet_aton(ip_buf,&my_addr);
    printf("ip : %s \n", ip_buf);
    printf("net: %x \n", my_addr.s_addr);
    return 0;
}

运行结果

[[email protected] 0827]$ gcc -o test test.c -Wall
[[email protected] 0827]$ ./test
ip : 180.97.33.107
net: 6b2161b4
照理,网络字节序是大端存储,应该返回0xb461216b。实际上调用系统函数inet_aton后,就直接在变量my_addr.s_addr的实际内存空间中以二进制形式写入了0xb461216b(其实用位运算,就可以直接操作二进制位,上篇博文有具体实现)。之所以运行结果是0x6b2161b4,是因为我们的主机是小端存储,用printf显示结果是先取低字节。

举例2

/*************************************************************************
    > File Name: test1.c
    > Author: KrisChou
    > Mail:[email protected]
    > Created Time: Wed 27 Aug 2014 11:43:26 PM CST
 ************************************************************************/

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    struct in_addr my_addr;
    my_addr.s_addr = 0xb461216b;
    printf("net: %x \n", my_addr.s_addr);
    printf("ip : %s \n", inet_ntoa(my_addr));
    return 0;
}
运行结果
[[email protected] 0827]$ gcc -o test1 test1.c -Wall
[[email protected] 0827]$ ./test1
net: b461216b
ip : 107.33.97.180
照理,ip应该输出的是180.97.33.107。其实道理很简单,我们的主机是小端模式存储,而网络字节序是大端模式,当我们把0xb461216b赋值给my_addr.s_addr 时,实际上在内存中存储形式是0x6b2161b4,而inet_ntoa的具体实现时通过位运算直接操纵二进制位的,因此结果就自然输出107.33.97.180。

函数原型2

SYNOPSIS
       #include <netdb.h>
       struct hostent *gethostbyname(const char *name);

The hostent structure is defined in <netdb.h> as follows:

           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 */
           }
           #define h_addr h_addr_list[0] /* for backward compatibility */

       The members of the hostent structure are:

       h_name The official name of the host.

       h_aliases
              An array of alternative names for the host, terminated by a NULL
              pointer.

       h_addrtype
              The type of address; always AF_INET or AF_INET6 at present.

       h_length
              The length of the address in bytes.

       h_addr_list
              An  array of pointers to network addresses for the host (in net-
              work byte order), terminated by a NULL pointer.

       h_addr The first address in h_addr_list for backward compatibility.

代码

/*************************************************************************
  > File Name: my_host.c
  > Author: KrisChou
  > Mail:[email protected]
  > Created Time: Wed 27 Aug 2014 05:22:46 PM CST
 ************************************************************************/

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(int argc, char* argv[])// exe hostname
{
    struct hostent* p ;
    p = gethostbyname(argv[1]) ;
    /*
    struct hostent {
        char  *h_name;
        char **h_aliases;
        int    h_addrtype;
        int    h_length;
        char **h_addr_list;
    }
#define h_addr h_addr_list[0]
 */
    printf("host name: %s \n", p ->h_name);

    int index ;
    char** pp  = p -> h_aliases ;
    for(index = 0 ; pp[index] != NULL; index ++ )
    {
        printf("alias : %s \n", pp[index]);
    }

    printf("ip type : %d\n", p ->h_addrtype);

    printf("addr len : %d \n", p ->h_length);

    pp = p ->h_addr_list ;
    for(index = 0; pp[index] != NULL ; index ++)
    {
        /* 由于h_addr_list是一个字符串指针数组,数组中存放的指针指向一个网络字节序
            但是系统函数inet_ntoa需要传入的参数是一个结构体,因此需要进行转换。
            pp[index]是一个char*类型的指针,先将其转换为struct in_addr*类型的指针,
            接着去引用,即得到结构体。                                                 */
        printf("ip : %s \n", inet_ntoa( *(struct in_addr *)pp[index] ) );
    }

    return 0 ;
}
运行结果
[[email protected] 0827]$ gcc -o myhost my_host.c -Wall
[[email protected] 0827]$ ./myhost www.baidu.com
host name: www.a.shifen.com
alias : www.baidu.com
ip type : 2
addr len : 4
ip : 180.97.33.107
ip : 180.97.33.108

干货

某年腾讯面试题:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int a = 0x61;//97
    printf("%x\n",(char*)(&a)[0]);
}

结果输出61,说明是小端机,先存低字节。

总结

切记系统函数无论inet_aton还是inet_ntoa,都是直接以位运算形式实现的,因此其关注的是数据在内存中实际的二进制存储形式。

时间: 2024-10-09 06:52:21

Linux网络编程2——系统函数的相关文章

linux网络编程:select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET(转)

从别人的博客中转载过来了这一篇文章,经过重新编辑排版之后展现于此,做一个知识点保存与学习. select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复用输入/输出模型,原型: int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout); 所在的头文件为:#include <sys/time.h> 和#include <uni

linux 网络编程 inet_pton &amp; inet_ntop函数

#include <arpa/inet.h> int inet_pton(int family,const char * strptr,void * addrptr); 返回:1--成功, 0--输入不是有效的表达格式 , -1--出错 const char * inet_ntop(int family,const void * addrptr,char * strptr,size_t len); 其中len =sizeof(* strptr) 返回: 指向结果的指针--成功 , NULL--

Linux网络编程函数

转自:http://blog.csdn.net/hrbeuwhw/article/details/8050911 1.字节序函数 #include<netinet.h> uint16_t htons(uint16_t host16bitvalue); uint32_t htonl(uint32_t host32bitvalue); 返回:网络字节序值 uint16_t ntohs(uint16_t net16bitvalue); uint32_t ntohl(uint32_t net32bit

linux网络编程九:splice函数,高效的零拷贝

from:http://blog.csdn.net/jasonliuvip/article/details/22600569 linux网络编程九:splice函数,高效的零拷贝 最近在看<Linux高性能服务器编程>,在此做个日记,以激励自己,同时分享于有需要的朋友. 1. splice函数 [cpp] view plain copy #include <fcntl.h> ssize_t splice(int fd_in, loff_t *off_in, int fd_out, 

很全的linux网络编程技巧

注:作者王晓,本人认为总结得很好,故记之,绝无侵权之意. 1. LINUX网络编程基础知识 1 1.1. TCP/IP协议概述 1 1.2. OSI参考模型及TCP/IP参考模型 1 1.3. TCP协议 3 1.4. UDP协议 5 1.5. 协议的选择 6 2. 网络相关概念 6 2.1. socket概念 7 2.2. socket类型 8 2.3. socket信息数据结构 8 2.4. 数据存储优先顺序的转换 8 2.5. 地址格式转化 9 2.6. 名字地址转化 10 3. sock

Linux网络编程(一)

1.socket     int socket(int domain, int type,int protocol) domain:说明我们网络程序所在的主机采用的通讯协族(AF_UNIX和AF_INET等). AF_UNIX只能够用于单一的Unix系统进程间通信,而AF_INET是针对Internet的,因而可以允许在远程 主机之间通信(当我们 man socket时发现 domain可选项是 PF_*而不是AF_*,因为glibc是posix的实现 所以用PF代替了AF,不过我们都可以使用的

linux网络编程学习笔记之二 -----错误异常处理和各种碎碎(更新中)

errno 在unix系统中对大部分系统调用非正常返回时,通常返回值为-1,并设置全局变量errno(errno.h),如socket(), bind(), accept(), listen().erron存放一个正整数来保存上次出错的错误值. 对线程而言,每个线程都有专用的errno变量,不必考虑同步问题. strerror converts to English (Note: use strerror_r for thread safety) perror is simplified str

Linux网络编程入门 (转载)

http://www.cnblogs.com/RascallySnake/archive/2012/01/04/2312564.html (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户端        在网络程序中,如果一个程序主动和外面的程序通信,那么我们把这个程序称为客户端程序. 比如我们使用ftp程序从另外一        个地方获取文件

Linux网络编程(二)

服务套和客户机的信息函数 1.字节转换函数 在网络上面有着许多类型的机器,这些机器在表示数据的字节顺序是不同的, 比如i386芯片是低字节在内存地址的低端,高字节在高端,而alpha芯片却相反. 为了统一起来,在Linux下面,有专门的字节转换函数. unsigned long int htonl(unsigned long int hostlong)     unsigned short int htons(unisgned short int hostshort)     unsigned