目录
socket(套接字)
引入
我们已经知道,ip地址可以标识全网唯一的一台主机,而端口号可以标识一台主机上唯一的一个进程
那么如果两者结合起来使用 -- id : port
- 它就可以标识全网唯一的一个进程
介绍
所以,套接字其实就是基于ip地址和端口号通信的一种方式
套接字提供了通信的端点,一个套接字可以与另一个套接字进行连接,从而实现数据的传输
- socket的意思是插座
- 使用socket通信的两台主机,就像插头插在插座上,只要通电就可以传输信息
统一接口
引入
网络通信有很多场景:
- 主机内的进程间通信
- 不同用户(不同主机)间的网络通信
套接字提供了一种统一的编程接口,使得在不同的网络通信场景下可以使用相似的方法来实现数据传输
为什么要统一呢?
- 自然是为了方便我们使用,难道换一个场景就换一套接口吗,那学习成本也太大了
- 就像操作系统的系统调用一样,不同的软件可以使用相同的接口与os交互
- 反正都是要操作os,规定一套总比大家各用各的好
- 这里也是一样,反正都是要使用网络资源,规定一套统一的网络编程接口更好一点
实现
- 不同的场景使用的结构体不同,因为需要的字段不同
- 如果要统一,就必须先统一类型
- 也就是说 -- 上层用统一的类型,下层根据某个标识字段/其他规定来区分具体是哪个类型,以调用对应的变量和方法
- 就像计算机管理硬件资源那样:
这也就是多态的思想
sockaddr结构
介绍
socket接口中,大多数都有struct sockaddr*这个结构体指针类型(这个就是那个统一的类型,网络中使用的信息都是从这个结构体拿的):
- 用于表示套接字地址信息的通用结构
他有两个变体(可以看作继承里的子类):
可以看到,两个不同的结构体,有相同的2字节的地址类型
- 所以在统一的结构体中也存放该字段,这样只要识别一下填充的数据,就可以知道当前是哪个结构体类型了
- 这样就可以使用通用的接口,使用不同的套接字结构体,用于不同的场景
为什么是这种形式
为什么一定要通过这种方式来接收不同类型的指针呢?
直接用void*,然后强转成short类型提取出前2个字节进行识别不好吗?
- 确实挺好
- 但当时这套接口设计出来前,还没有void*
- 虽然之后有了更好的方法,但我们没法去修改
sockaddr_in
介绍
在套接字编程中用于表示ipv4地址的结构体,定义在<netinet/in.h>中
下图是结构体的定义:
- sin的意思 -- socket inet
sin_family
类型
这里是用宏的形式,定义了一个sa_family_t类型(也就是无符号整型)的sin_family变量(涉及到c语法的宏拼接)
作用
指定了套接字地址的类型,可以根据地址类型字段确定结构体中的内容
- 例如 IPv4 或 IPv6
- 其中,AF_INET=PT_INET(两种都可以)
sin_port
表示端口号
类型是in_port_t :
16位的无符号整数类型
sin_addr
是一个结构体对象:
内部仅有一个变量:
用于存放ip地址(是32位的整数,用户一般使用的是字符串类型的ip地址"xxx.xxx.x.x")
sin_zero
填充字段(占位符)
- 以确保结构体的大小与sockaddr结构体保持一致
sockaddr_un
介绍
表示Unix域套接字地址的结构体
Unix域套接字是一种在同一台主机上的进程之间进行通信的机制
sin_family
和前面的一样,指定地址家族:
通常为AF_UNIX
sun_path
存储Unix域套接字文件的路径名。路径名的最大长度为 108 个字符,包括终止的 null 字符
ifconfig
查看网络接口信息
- 包含两种接口 -- 网络接口,回环接口
eth0
inet
- 主机的ipv4地址
- 以.分割的每个区域,取值范围都是255
ether(以太)
- 以冒号分割的一个字节的16进制数,总共48bit
- 也就是我们的mac地址
lo (loopback)
用于本地主机通信
包含的信息和上面的类似,只不过没有mac地址(因为不涉及局域网通信)
127.0.0.1 本地环回地址
- 如果套接字绑定的是这个ip地址,那么该进程发送的消息不会送到网络,而是贯穿协议栈后又回来了
- 一般用于cs的测试