《unix网络编程》(7)socket概述

socket

什么是socket

        socket可以看成是用户进程与内核网络协议栈的接口(编程接口, 如下图所示),其不仅可以用于本机进程间通信,可以用于网络上不同主机的进程间通信,甚至还可以用于异构系统之间的通信。

《unix网络编程》(7)socket概述_第1张图片


IPv4套接字地址结构

         IPv4套接口地址结构通常也称为“网际套接字地址结构”,它以“sockaddr_in”命名,定义在头文件中。TPv4地址和TCP或UDP端口号在套接字地址结构中总是以网络字节序存储的。

        套接字地址结构仅在给定主机上使用:虽然结构的某些字段(IP、端口)可以用在不同主机之间的通信,但是结构本身并不在主机之间传递

struct in_addr {
    in_addr_t s_addr;      //32位IPv4地址,网络字节序
};
struct sockaddr_in
{
    uint8_t  sin_len;
    sa_family_t  sin_family;
    in_port_t	sin_port;	      //2字节
    struct in_addr	sin_addr;     //4字节
    char sin_zero[8];	              //8字节
 };

/*
成员说明:
    sin_len:整个sockaddr_in结构体的长度,在4.3BSD-Reno版本之前的第一个成员是sin_family.
    sin_family:指定该地址家族,对于IPv4来说必须设为AF_INET
    sin_port:端口
    sin_addr:IPv4的地址;
    sin_zero:暂不使用,一般将其设置为0
*/

通用套接字地址结构

        问题:当作为一个参数传递进任何套接字函数时,套接字地址结构总是以引用形式(指向该结构的指针)来传递的。套接字函数必须能够处理任何协议族中套接字的地址结构。在如何声明指针的数据类型上存在一个问题。解决方法:ANSI C之后解决方法是:void *作为通用的指针类型。然而套接字函数是先于ANSI C的,所以采取的方式是头文件中定义一个通用的套接字地址

struct sockaddr
{
	uint8_t  sin_len;
	sa_family_t  sin_family;
	char sa_data[14]; 	//14字节   
};
/*
说明:
    sin_len:整个sockaddr结构体的长度
    sin_family:指定该地址家族
    sa_data:由sin_family决定它的形式。
*/
ANSI C中bind函数原型为:

int bind(int, struct sockaddr*, socklen_t);
那么, 任何对这些函数的调用都需要将特定协议的套接字地址结构的指针进行强制类型转换,变为指向某个通用套接字地址结构的指针,例如:

struct sockaddr_in serv;
bind(sockfd, (struct sockaddr*) &serv, sizeof(serv));

值-结果参数

套接口地址结构是在进程和内核中之间传递的。
1.   从进程到内核传递套接口地址结构有三个函数:bind, connet和senddto,这三个函数的一个参数是指向套接字地址结构的一个指针,另一个参数是结构的整数大小。例如:

     struct sockaddr_in serv;
     connect(sockfd, (SA*)&serv, sizeof(serv));
通过将指针和指针所指向结构的大小传递给内核,那么从进程到内核的过程便知道了要拷贝数据的多少。

2.  从内核到进程传递套接口地址结构有四个函数: accept, recvfrom, getsockname和getpeername。这四个函数的其中两个相同参数是:指向套接口地址结构的指针和指向表示结构大小的整数的指针,例如:  

     struct sockaddr_un cli;
     socklen_t len = sizeof(cli);
     getpeername(unixfd, (SA*)&cli, &len);

        之所以将结构大小由整数转为指向整数的指针,是因为:当函数被调用时,结构大小是一个值(value,该值告诉内核该结构的大小,避免数据的读取越界);当函数返回时,结构大小是一种结果(result,内核通过此结果来告诉进程它在这结构里实际存储了多少信息)。因此这种类型的参数叫做值-结果(value-result)参数

《unix网络编程》(7)socket概述_第2张图片

常用函数

字节序转换函数

为什么进行字节序转换以及字节序转换函数,参考文章《unix网络编程》(6)网络字节序 大端模式和小端模式


地址转换函数

//这组用于在点分十进制和32位网络字节序的二进制之间转换Ipv4地址
#include 
#include 
int inet_aton(const char *cp, struct in_addr *inp);  //返回:若字符串有效为1,否则为0
in_addr_t inet_addr(const char *cp);	//返回:若字符串有效返回32位二进制网络字节序IPv4地址,否则INADDR_NONE
char *inet_ntoa(struct in_addr in);     //返回:指向一个点分十进制数串的指针
         inet_addr函数存在一个问题:函数出错返回INADDR_NONE常数,而该值在32位系统中通常为1,这意味着地址255.255.255.255(ipv4广播地址)不能使用该函数处理,因为该地址二进制被用来指示该函数失败。因此inet_addr函数 已经不再使用,而使用inet_aton。


另外一组函数对IPv4和IPv6均适用,p表示表达(presentation),n表示数值(numeric)。地址的表达格式通常是ASCII码字符串,数值格式则是放在套接字地址结构中的二进制值。

#include 
int inet_pton(int family, const char *strptr, void *addrptr); //返回:成功返回1,若输入的不是有效表达式返回0,出错返回-1
int char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len); //返回:成功返回结果的指针,出错返回NULL



你可能感兴趣的:(UNIX网络编程,Ubuntu下实现的网络编程)