unix网络编程 套接字

Posted on 2019-12-07 16:49  辉仔猿  阅读(633)  评论(0编辑  收藏  举报

第三章 套接字编程简介

大多数套接字函数都需要一个指向套接字地址结构的指针作为参数。每个协议族都定义了它的套接字地址结构。这些结构的名字均已sockaddr_开头,并以对应的唯一后缀结束。

1.套接字地址结构

IPv4套接字结构

IPv4套接字地址结构通常称为“网际套接字地址结构”,它以sockaddr_in命名,定义在<netinnet/in.h>头文件中。

以下是网际(IPv4)套接字地址结构:sockaddr_in

struct in_addr;
{
   int_addr_t s_addr; /*32位IPv4的地址*/
                      /*网络字节命令*/
};

struct sockaddr_in 
{
uint8_t     sin_len;
sa_family_t sin_family;
in_port_t   sin_port;

struct in_addr sin_addr;
char           sin_zero[8];
};

长度字段sin_len是为了增加对OSI协议的支持而随4.3BSD-Reno添加到。(因为有了长度字段,才简化了长度可以变套接字地址结构的处理)

POIX规范只需要这个结构中的3个字段:sin_family、sin_add、sin_port。对于符合POIX的实现来说,定义额外的结构字段是可以接收的,这对于网际套接字地址结构来说也是正常的。几乎所有的实现都增加了sin_zero字段,所以所有的套接字地址结构大小都至少是16字节。

数据类型 说明 头文件
int8_t 带符号的8位整数 <sys/typcs.h>
uint8_t 无符号的8位整数 <sys/typcs.h>
int16_t 带符号的16位整数 <sys/typcs.h>
uint16_t 无符号的16位整数 <sys/typcs.h>
int32_t 带符号的32位整数 <sys/typcs.h>
uint32_t 无符号的32位整数 <sys/typcs.h>
sa_family_t 套接字地址结构的地址族 <sys/socket.h>
socklen_t 套接字地址结构的长度,一般为uint32_t <sys/socket.h>
in_addr_t

IPv4地址,一般为unit32_t

<netine/in.h>
in_port_t TCP或UDP端口,一般为uint16_t <netine/in.h>

(扩展)POSIX(Portable Operating System Interface,可移植操作系统接口)

POIX是接口。

POSIX标准定义了操作系统应该为应用程序提供的接口标准,是IEEE为要在各种UNIX操作系统上运行的软件而定义的一系列API标准的总称,其正式称呼为IEEE 1003,而国际标准名称为ISO/IEC 9945。

(一些常见的缩写)

addr(address,地址)

info(information,信息)

通用套接字地址结构

通用套接字地址结构:sockaddr

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

IPv6套接字地址结构

IPv6套接字地址结构在<netinet/in.h>头文件中定义

struct in6_addr
{
unit8_t s6_add[16];

};

#define SIN6_LEN
struct sockaddr_in6
{ 
uint8_t           sin6_len;
sa_family_t       sin6_family;
in_port_t         sin6_port;
uint32_t          sin6_flowinfo;
struct in6_addr   sin6_addr;
uint32_t          sin6_scope_id;
};

新的通用套接字地址结构

新的struct sockaddr_storage足以容纳系统所支持的任何套接字地址结构。sockaddr_storage结构在<netinet/in.h>头文件中定义

struct sockaddr_storage
{
uint8_t       ss_len;
sa_family_t   ss_family;
};

不同套接字地址结构的比较

2.值-结果参数

传递方式取决于该结构的传递方向:是从进程到内核,还是从内核到进程、

1)从进程到内核传递套接字地址结构的函数有3个:bind,connect和sendto

这些函数的一个参数时指向某个套接字地址结构的指针,另一个参数时该结构的整数大小。

!!套接字地址结构大小的数据类型是socklen_t。(POIX建议将socklen_t定义为uint32_t)

2)从内核到进程传递套接字地址结构的函数有4个:accept,recvfrom,getsocknamo和getpeername。

这4个函数的其中两个参数是指向某个套接字地址结构的指针和指向表示该结构大小的整数变量的指针。

值-结果参数:把套接字地址结构大小这个参数从一个整数改为指向某个整数变量的指针,其原因在于,当函数被调用时,结构大小是一个值,它告诉内核该结构的大小,这样内核在写该结构时不至于越界;

当函数返回时,结构大小又是一个结果,它告诉进程内核在该结构中究竟储存了多少信息。

3.字节排序函数

小端和大端(内存中存储两个字节有两种方法)

小端(little-endian):将低序字节存储在起始地址

大端(big-endian):将高序字节存储在起始地址

主机字节序:某个给定系统所用的字节序

输出字节序的程序:

#iclude"unp.h"
int
main(int argc,char **argv)
{
  union{
     short   s;
     char    c[sizeof(short)];
        }un;
un.s=0x0102;
printf("%s:",CUP_VENDOR_OS);
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));
exit(0);
}

4.字节操纵函数

bzero:bzero把目标字节串指定数目的字节置为0。我们常用该函数把一个套接字地址结构初始化为0.

bocpy:指定数目的字节从源字节串移动到目标字节串。

bcmp:比较两个任意的字节串,若相同返回值为0,否则返回值为非0.

memset:把目标字节串指定数目的字节置为c。

mencmp:比较两个任意的字符串,若相同为0,否则返回一个非0值,是大于0还是小于0则取决于第一个不等的字节。

5.inet_aton、net_addr和inet_ntoa函数(地址转换函数)

6.inet_pton和inet_ntop函数

函数中的p代表表达(presentation),n代表数值(numeric)

地址的表达格式通常是ASCII字符串,数值格式则是存放到套接字地址结构中的二进制。

1)只支持IPv4的inet_pton函数的简单定义

int
inet_pton(int family,const char *strptr,void *addrptr)
{
    if(family==AF_INET)
    {
         struct in_addr  in_val;
    if(inet_aton(strptr,&in_val))
    {
        memcpy(addrptr,&in_val,sizeof(struct int_addr));
        return(1);
    }
    return(0);
    }
    errno=EAFNOSUPPROT;
    return(-1);
}

2)只支持IPv4的inet_ntop函数的简化版本

const char*
inet_ntop(int family,const void *addrptr,char *strptr,size_t len)
{
   const u_char *p=(const u_char *)addrptr;
   if(family==AF_INET)
   {char temp[INET_ADDRSTRLEN];
   snprintf(temp,sizeof(temp),"%d,%d,%d,%d",p[0],p[1],p[2],p[3]);
   if(strlen(temp)>=len)
   { errno=ENOSPC;
     return (NULL);
   }
   strcpy(strptr,temp);
   return (strptr);
}
errno =EAFNOSUPPORT;
return (NULL);
}
    

 

7.sock_ntop和相关函数

作用:它以指向某个套接字地址结构的指针为参数,查看该结构的内部,然后调用适当的函数返回该地址的表达格式。

#include"unp.h"
char *sock_ntop(const struct sockaddr *sockaddr,socklen_t addrlen);
//若成功则为非空指针,若出错为NULL

!!sock是什么?很多时候我们在写代码为了表达清楚这个元素背后的意思,我们都会采用英文单词的缩写。例如这个sock是套接字的英文(socket)的缩写。然后我们可以结合它的意思来理解这些元素的意义,例如sockaddr指的是套接字的套接字的地址,socklen指的是套接字的长度。虽然看到一大串英文字母感到贼烦,但是很多只要理解意思之后就没有那么可怕了。嘻嘻。