linux 服务器编程学习(一)基本函数和结构体

socket地址表示

socket地址一般包括两部分:地址族和地址值(不同的协议族有不同的含义)

地址族

AF_UNIX---------unix本地协议族--------------文件路径名
AF_INET----------TCP/IPv4协议族------------16bit端口号和32bitipv4地址,共6字节
AF_INET6--------TCP/IPv6协议族------------16bit端口号,32bit流标识,128bitipv6地址,32bit范围ID,共26字节

socket结构体

不同的协议族包含的地址信息是不同的,有一个通用的socket地址可以用于承载所有的协议类型的地址,也有对应的专用socket地址结构体去表示某一特定的协议族的地址,比如sockaddr_in表示AF_INET协议族地址,因此结构体包含三部分即端口号,inv4地址和协议族;sockaddr_un包含文件路径名和协议族两部分等。
通用socket地址----sockaddr
专用socket地址----sockaddr_un(本地)----sockaddr_in(ipv4)----sockaddr_in6(ipv6)
ip地址----in_addr(ipv4)----in6_addr(ipv6),专用socket地址中包含ip地址。
sockaddr

struct sockaddr
  {
    __SOCKADDR_COMMON (sa_);	/* Common data: address family and length.  */
    char sa_data[14];		/* Address data.  */
  };

sockaddr_un

struct sockaddr_un
  {
    __SOCKADDR_COMMON (sun_);
    char sun_path[108];		/* Path name.  */
  };

sockaddr_in:

struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;			/* Port number.  */
    struct in_addr sin_addr;		/* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr)
			   - __SOCKADDR_COMMON_SIZE
			   - sizeof (in_port_t)
			   - sizeof (struct in_addr)];
  };

sockaddr_in6

struct sockaddr_in6
  {
    __SOCKADDR_COMMON (sin6_);
    in_port_t sin6_port;	/* Transport layer port # */
    uint32_t sin6_flowinfo;	/* IPv6 flow information */
    struct in6_addr sin6_addr;	/* IPv6 address */
    uint32_t sin6_scope_id;	/* IPv6 scope-id */
  };

这里都包含一个__SCKIADDR_COMMON,定义如下:

#define	__SOCKADDR_COMMON(sa_prefix) \
  sa_family_t sa_prefix##family

这是一个宏替换,_SOCKADDR_COMMON(sin6)就相当于定义为 sa_family_t sin6_family;

typedef unsigned short int sa_family_t;

sockaddr_in因为经常要转换到sockaddr,在结构体的最后定义了0填充来保持和sockaddr占用的总空间大小相同。

ip地址转换函数

ip地址转换函数一般用于在字符串表示的ip地址(比如“127.0.0.1”)和二进制网络字节序之间进行转换
in_addr_t inet_addr(const char * strptr);
用于将字符串表示的ip地址转换为网络字节序表示的ipv4地址,ip_addr_t等价于unit32,结构体ip_addr中存储一个ip_addr_t;
int inet_aton(const char* cp, struct in_addr* inp);
和inet_addr功能相同,但是将转换结果存储到inp中。
char* inet_ntoa(struct in_addr in);
和inet_aton作用相反。

/* Convert Internet number in IN to ASCII representation.  The return value
   is a pointer to an internal array containing the string.  */
extern char *inet_ntoa (struct in_addr __in) __THROW;

这里n和a的解释分别是IN(网络字节序二进制)和ASCII;
且inet_ntoa用一个静态变量存储转换结果,因此多次连续转换后者会覆盖前者。
地址转换相关的函数还有
inet_pton (int __af, const char *__restrict __cp, void *__restrict __buf)
inet_ntop (int __af, const void *__restrict __cp,char *__restrict __buf, socklen_t __len)

/* Convert from presentation format of an Internet number in buffer
   starting at CP to the binary network format and store result for
   interface type AF in buffer starting at BUF.  */
extern int inet_pton (int __af, const char *__restrict __cp,
		      void *__restrict __buf) __THROW;

/* Convert a Internet address in binary network format for interface
   type AF in buffer starting at CP to presentation form and place
   result in buffer of length LEN astarting at BUF.  */
extern const char *inet_ntop (int __af, const void *__restrict __cp,
			      char *__restrict __buf, socklen_t __len)
     __THROW;

这里为了和aton中的a进行区分用p(presentation format)表示字符串ipv4,ipv6地址,相比aton这两个函数对ipv4piv6都能够进行转换。
还有个宏__THROW等价于throw(),表示不抛出任何异常(不得不说宏用的是真的多)

一个小例子

void test2()
{
    char ip1[] = "192.168.0.74";
     char ip2[] = "211.100.21.179";
     struct in_addr addr1, addr2;
     long l1, l2;
     l1 = inet_addr(ip1);   //将字符串形式的IP地址 -> 网络字节顺序  的整型值
     l2 = inet_addr(ip2);
     printf("IP1: %s\n IP2: %s\n", ip1, ip2);
     printf("Addr1: %ld\n Addr2: %ld\n", l1, l2);
     memcpy(&addr1, &l1, 4); //复制4个字节大小
     memcpy(&addr2, &l2, 4);
     printf("%s <--> %s\n", inet_ntoa(addr1), inet_ntoa(addr2)); //注意:printf函数自右向左求值、覆盖
     printf("%s\n", inet_ntoa(addr1)); //网络字节顺序的整型值 ->字符串形式的IP地址
     printf("%s\n", inet_ntoa(addr2));
     printf("%s\n", inet_ntoa(addr2));
}

结果如下
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值