第三章 套接字编程简介

1. IPV4地址结构:

#include <netinet/in.h>

struct in_addr
{
    int_addr_t s_addr;  //一般为uint32_t
};

struct sockaddr_in
{
    uint8_t                sin_len;     //一般用不上
    sa_family_t            sin_family;  //通常是uint_8
    in_port_t              sin_port;    //一般为uint16_t
    struct int_addr        sin_addr;
    char                   sin_zero[8];
}

2. 地址和端口号一般以网络字节序来存储。

3. 通用套接字地址结构:

#include <sys/socket.h>

struct sockaddr
{
    uint8_t          sa_len; 
    sa_family_t      sa_family;
    char             sa_data[14];
}

通过sa_family值确定此结构的真实类型

4. ipv6地址结构    

struct in6_addr
{
    uint8_t s6_addr[16];
};

struct sockaddr_in6 {
    uint8_t              sin6_len;
    sa_family_t        sin6_family;   /* AF_INET6 */
    in_port_t           sin6_port;     /* port number */
    uint32_t            sin6_flowinfo; /* IPv6 flow information */
    struct in6_addr  sin6_addr;     /* IPv6 address */
    uint32_t            sin6_scope_id; /* Scope ID (new in 2.4) */
};

套接字地址结构比较图

 

5. 值-结果参数的含义:

如有以下函数调用:

struct AAA st;

int len = sizeof(st);

func(&st, &len)

len是结构st的大小,用于防止func函数内部引用st时越界,函数返回时会通过len值告诉调用者,func函数存储了st中多少信息。如select,getsockopt,recvmsg,sysctl等函数中有这种应用。

6. 字节排序,little-endian与big-endian

#include <netinet/in.h>

//主机字节序转换为网络字节序
uint16_t htons(uint16_t  host_value);

uint32_t htonl(uint32_t host_value);

//网络字节序转换为主机字节序
uint16_t ntohs(uint16_t  net_value);

uint32_t ntohl(uint32_t net_value);

判断系统所用字节序程序:

View Code
int main()
{
    union
    {
        short s;
        char c[sizeof(short)];
    }un;

    un.s = 0x0102;

    if (sizeof(short) == 2)
    {
        if (un.c[0] == 1 && un.c[1] == 2)
        {
            printf("big-endian\n");
        }
        else if (un.c[0] == 2 && un.c[1] == 1)
        {
            printf("little-endian\n");
        }
        else
        {
            printf("unknown\n");
        }
    }
    else
    {
        printf("sizeof(short) = %d\n", sizeof(short));
    }
    return 0;
}

7. 字节操作函数

1)Berkeley的函数

#include <string.h>

void bzero(void *dest, size_t nbytes);

void bcopy(const void *src, void *dest, sizt_t nbytes); 

int bcmp(const void *ptr1, const void *ptr2, size_t nbytes);

2)ANSI C的函数

#include <string.h>

void *memset(void *dest, int c, size_t len);

void *memcpy(void *dest, const void *src, size_t nbytes);

int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);

两者比较 : memcpy与bcopy参数位置相反,当源字符串和目标字符串重叠时bcopy能处理而memcpy则不能,需要用memmove代替。

8. 地址转换函数

1)适用于ipv4

#include <arpa/inet.h>

//有效返回1,否则返回0
int inet_aton(const char *strptr, struct in_addr *addrptr);

//注意为什么参数为结构而不是指针?
char *inet_ntoa(struct in_addr inaddr);

in_addr_t inet_addr(const char *strptr); //此函数已废弃,不要用

2)ipv4,ipv6均适用

#include <arpa/inet.h>

//返回:成功1,输入有误0,出错-1
int inet_pton(int family, const char *strptr, void *addrptr);

//返回:成功返回指向结果指针,失败返回NULL
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

strptr的长度len在<netinet/in.h>头文件中有如下定义:

#define  INET_ADDRSTRLEN 16

#define  INET6_ADDRSTRLEN 46

总结:即使系统不支持IPv6也要用后面两个函数代替只支持ipv4的函数,保证代码与协议的无关性。

9. sock_ntop函数及相关函数是非标准库函数,此系列函数是为了方便编写与IPv4和IPv6协议无关的代码而封装的函数。

原文地址:https://www.cnblogs.com/4tian/p/2622544.html