IPV4IPV6 兼容的socket编程
----by Charles(morneve@gmail)
套接字Socket可以看成在两个程序进行通讯连接中的一个端点,一个程序将一段信息写入Socket中,该Socket将这段信息发送给另外一个Socket中,使这段信息能传送到其他程序中。
生成套接字,主要有3个参数:通信目的IP地址、使用的协议,使用的端口号。通过将这3个参数结合起来,应用层就可以和传输层(或网络层)通过套接字接口,区分来自不同应用程序进程或网络连接的通信。
Socket通讯流程图:
TCP编程的服务器端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt(); * 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();
4、开启监听,用函数listen();
5、接收客户端上来的连接,用函数accept();
6、收发数据,用函数send()和recv(),或者read()和write(); 之后close(clientsocket);
7、关闭网络连接; close(socket)
TCP编程的客户端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
4、设置要连接的对方的IP地址和端口等属性;
5、连接服务器,用函数connect();
6、收发数据,用函数send()和recv(),或者read()和write();
7、关闭网络连接;
UDP编程的服务器端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();
不需要listen()
4、数据交互,用函数recvfrom(); sendto()
5、关闭网络连接;
UDP编程的客户端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
4、设置对方的IP地址和端口等属性;
函数connect();* 可选
5、数据交互,用函数sendto(); recvfrom();
如果调用了connect就直接可以用send和recv了,这时最后两个参数会自动用connect建立时的地址信息填充
6、关闭网络连接;
几个Socket 地址结构相关结构体
注:在操作系统(内核)不同情况下,首两个字节可能是length+family
#ifdef ISC_PLATFORM_HAVESALEN
    ntp_u_int8_t    ss_len;        /* address length */
    ntp_u_int8_t    ss_family;    /* address family */
#else
    short        ss_family;    /* address family */
#endif
struct in_addr {
  u_int32_t s_addr;    /* 4bytes, IPv4 address */
};
=4
struct in6_addr {
      u_int8_t  s6_addr[16];  /* IPv6 address */
}
=16
一般socket函数都是传入的这个类型指针
struct sockaddr {
    sa_family_t    sa_family;      /* unsigned short address family, AF_xxx      */
    char            sa_data[14];    /* 14 bytes of protocol address */
};
2+14=16
struct sockaddr_in {
  short int sin_family; /* Address family */
  unsigned short int sin_port; /* Port number */
  struct in_addr sin_addr; /* Internet address */
  unsigned char sin_zero[8]; /* Same size as struct sockaddr */
};
2+2+4+8=16
struct sockaddr_in6{
sa_family_t sin6_family; //地址簇类型,为AF_INET6
in_port_t sin6_port; //16 位端口号,网络字节序
uint32_t sin6_flowinfo; //32 位流标签
struct in6_addr sin6_addr; //128 位IP 地址
/*uint32_t  sin6_scope_id;*/(新版本可能会多4字节scope id, RFC2553)
}
2+2+4+16=24
#define UNIX_PATH_MAX  108
struct sockaddr_un {
        sa_family_t sun_family; /* AF_UNIX,本地进程通讯*/
        char sun_path[UNIX_PATH_MAX];  /* pathname */
};
=110
结构体sizeof例:
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH, sizeof(my_addr.sun_path) - 1);
sockaddr_storage能提供严格的结构对齐
sockaddr_storage能容纳系统支持的更大的地址结构,容器
在使用sockaddr_storage定义的变量时,尽量强制转换成struct sockaddr, struct sockaddr_in, struct sockaddr_in6后操作
struct __kernel_sockaddr_storage {
        unsigned short  ss_family;              /* address family */
        /* Following field(s) are implementation specific */
        char            __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
                                /* space to achieve desired size, */
                                /* _SS_MAXSIZE value minus size of ss_family */
} __attribute__ ((aligned(_K_SS_ALIGNSIZE)));  /* force desired alignment */
#define sockaddr_storage __kernel_sockaddr_storage
=128
不同于sockaddr_storag的一个IPV4,IPV6兼容结构体(来源于busybox)
typedef struct len_and_sockaddr {
    socklen_t len;
    union {
        struct sockaddr sa;
        struct sockaddr_in sin;
        struct sockaddr_in6 sin6;
    };
} len_and_sockaddr;
用struct sockaddr_storage的好处,看:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。