最后更新:2019-10-25
一 基本概念
socket, 又称为"套接字"或者"插座". 是操作系统提供的一种进程间通信机制.目前大多用于不同网络设备之间的通信. socket 位于应用层与传输层之间, 通过传递给 socket 不同的参数, socket 最终选择不一样的协议(TCP/UDP等), 也就是说 socket 其实传输层协议簇的软件抽象.
图片来自于网络
1.1 流程概述
在网络应用中, 通信的两个进程之间主要用的是客户端/服务器 (C/S)模式, 即客户向服务器发出服务请求,服务器接收到请求后,提供相应的服务. socket 最开始设计于 Unix, Unix/Linux 设计哲学是 "一切皆文件", 因此,我们可以像文件操作(open/read/write/close)一样来操作 socket.
下图展示展示 C/S 之间如何使用 socket
对于 TCP 服务端来说:
- 创建 socket, 创建一个通信断点描述符, 但在进程中为未打开状态;
- 绑定(bind) socket, 将 socket 绑定到某个地址以及端口上;
- 监听(listen) socket, 用于表示该 socket 为一个被动链接(passive socket), 可以理解为 服务器的socket,需要客户端来主动连接了;
- 接收客户端的请求(accept), 服务端通过该方法接收客户端的连接请求;
- 读(read)/写(write)
- 关闭 socket
对于客户端来说就比较的简单: 创建一个socket, 然后连接服务器(connect), 完成对应的数据操作(读写), 完成后关闭(close);
二 socket 相关接口
2.1 创建 socket()
int socket(int domain, int type, int protocol);
socket 创建返回一个 socket 描述符, 跟文件描述符类似,后面的读写都需要依赖于这个描述符.
2.1.1 参数-协议族(domain)
协议族决定了使用的 socket 地址类型;
- Unix 域 socket:
AF_UNIX
或AF_LOCAL
, 使用地址类型为:struct sockaddr_un
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* Pathname */
};
AF_INET
, ipv4, 使用地址类型为:struct sockaddr_in
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
AF_INET6
, ipv6, 使用地址类型为:sockaddr_in6
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* port number */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */
};
struct in6_addr {
unsigned char s6_addr[16]; /* IPv6 address */
};
- 其他类型(
AF_X25
/AF_AX25
/AF_NETLINK
等),其他类型目前还没有涉及到,不做过多讨论,感兴趣可以访问手册进行研究;
2.1.2 参数-类型(type)
表示 socket 通信的类型
- SOCK_STREAM: 可靠的面向流服务或流套接字 (TCP)
- SOCK_DGRAM: 数据报文服务或者数据报文套接字 (UDP)
- SOCK_SEQPACKET:可靠的连续数据包服务
- SOCK_RAW: 网络层之上自行指定运输层协议头,即原始套接字
2.1.3 参数-协议类型(protocol)
指定实际使用的传输协议, 传 0 表示根据前面的 domain 和 type 选择协议;
2.2 其他函数略过
其他的函数没有什么特别需要注意的地方,直接参考下面例子以及手册就能看懂
三 示例程序-本地进程间通信
当给 socket()
的协议族传入(AF_UNIX
或 AF_LOCAL
)时,可表示Unix域socket, 用于本地进程间通信.
其中地址类型中的 sun_path
是一个值得注意的地方,根据文档所描述,有三种类型
+ pathname: 文件类型,这种文件需要服务端与客户端对文件都有操作权限, 程序执行过程中,可以看到对应的文件.
+ unnamed
+ abstract: 抽象类型, 这种类型与 pathname 区别在于,给 sun_path 的第一个值为