计算机里的套接字到底是什么

简介: 【4月更文挑战第3天】套接字在网络编程中扮演着重要角色,类似于电话和电话号码的概念。文章介绍了套接字的基本概念和工作原理,包括服务器端和客户端的初始化、连接建立、数据传输和断开连接的过程。

在网络编程中,我们经常会提到 socket 这个词,它的中文翻译为套接字,有的时候也叫做套接口。


那到底应该怎么理解 socket 呢?这张图表达的其实是网络编程中,客户端和服务器工作的核心逻辑。

image.png

先从右侧的服务器端开始看,因为在客户端发起连接请求之前,服务器端必须初始化好。右侧的图显示的是服务器端初始化的过程,首先初始化 socket,之后服务器端需要执行 bind 函数,将自己的服务能力绑定在一个众所周知的地址和端口上,紧接着,服务器端执行 listen 操作,将原先的 socket 转化为服务端的 socket,服务端最后阻塞在 accept 上等待客户端请求的到来。

此时,服务器端已经准备就绪。客户端需要先初始化 socket,再执行 connect 向服务器端的地址和端口发起连接请求,这里的地址和端口必须是客户端预先知晓的。这个过程,就是著名的 TCP 三次握手(Three-way Handshake)。


一旦三次握手完成,客户端和服务器端建立连接,就进入了数据传输过程。


客户端进程向操作系统内核发起 write 字节流写操作,内核协议栈将字节流通过网络设备传输到服务器端,服务器端从内核得到信息,将字节流从内核读入到进程中,并开始业务逻辑的处理,完成之后,服务器端再将得到的结果以同样的方式写给客户端。可以看到,一旦连接建立,数据的传输就不再是单向的,而是双向的,这也是 TCP 的一个显著特性。


客户端完成和服务器端的交互后,比如执行一次 Telnet 操作,或者一次 HTTP 请求,需要和服务器端断开连接时,就会执行 close 函数,操作系统内核此时会通过原先的连接链路向服务器端发送一个 FIN 包,服务器收到之后执行被动关闭,这时候整个链路处于半关闭状态,此后,服务器端也会执行 close 函数,整个链路才会真正关闭。半关闭的状态下,发起 close 请求的一方在没有收到对方 FIN 包之前都认为连接是正常的;而在全关闭的状态下,双方都感知连接已经关闭。


无论是客户端的 connect,还是服务端的 accept,或者 read/write 操作等,socket 是我们用来建立连接,传输数据的唯一途径。


把整个 TCP 的网络交互和数据传输想象成打电话,顺着这个思路想象,socket 就好像是我们手里的电话机,connect 就好比拿着电话机拨号,而服务器端的 bind 就好比是去电信公司开账号,将电话号码和我们家里的电话机绑定,这样别人就可以用这个号码找到你,listen 就好似人们在家里听到了响铃,accept 就好比是被叫的一方拿起电话开始应答。至此,三次握手就完成了,连接建立完毕。

接下来,拨打电话的人开始说话:“你好。”这时就进入了 write,接收电话的人听到的过程可以想象成 read(听到并读出数据),并且开始应答,双方就进入了 read/write 的数据传输过程。

最后,拨打电话的人完成了此次交流,挂上电话,对应的操作可以理解为 close,接听电话的人知道对方已挂机,也挂上电话,也是一次 close。


在整个电话交流过程中,电话是我们可以和外面通信的设备,对应到网络编程的世界里,socket 也是我们可以和外界进行网络通信的途径。


套接字的通用地址结构

/* POSIX.1g 规范规定了地址族为2字节的值.  */
typedef unsigned short int sa_family_t;
/* 描述通用套接字地址  */
struct sockaddr{
    sa_family_t sa_family;  /* 地址族.  16-bit*/
    char sa_data[14];   /* 具体的地址值 112-bit */
  };

在这个结构体里,第一个字段是地址族,它表示使用什么样的方式对地址进行解释和保存,好比电话簿里的手机格式,或者是固话格式,这两种格式的长度和含义都是不同的。地址族在 glibc 里的定义非常多,常用的有以下几种:

  • AF_LOCAL:表示的是本地地址,对应的是 Unix 套接字,这种情况一般用于本地 socket 通信,很多情况下也可以写成
  • AF_UNIX、AF_FILE;AF_INET:因特网使用的 IPv4 地址;
  • AF_INET6:因特网使用的 IPv6 地址。


常用的 IPv4 地址族的结构

/* IPV4套接字地址,32bit值.  */
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };
  
/* 描述IPV4的套接字地址格式  */
struct sockaddr_in
  {
    sa_family_t sin_family; /* 16-bit */
    in_port_t sin_port;     /* 端口号  16-bit*/
    struct in_addr sin_addr;    /* Internet address. 32-bit */
    /* 这里仅仅用作占位符,不做实际用处  */
    unsigned char sin_zero[8];
  };


glibc 定义的保留端口

/* Standard well-known ports.  */
enum
  {
    IPPORT_ECHO = 7,    /* Echo service.  */
    IPPORT_DISCARD = 9,   /* Discard transmissions service.  */
    IPPORT_SYSTAT = 11,   /* System status service.  */
    IPPORT_DAYTIME = 13,  /* Time of day service.  */
    IPPORT_NETSTAT = 15,  /* Network status service.  */
    IPPORT_FTP = 21,    /* File Transfer Protocol.  */
    IPPORT_TELNET = 23,   /* Telnet protocol.  */
    IPPORT_SMTP = 25,   /* Simple Mail Transfer Protocol.  */
    IPPORT_TIMESERVER = 37, /* Timeserver service.  */
    IPPORT_NAMESERVER = 42, /* Domain Name Service.  */
    IPPORT_WHOIS = 43,    /* Internet Whois service.  */
    IPPORT_MTP = 57,
    IPPORT_TFTP = 69,   /* Trivial File Transfer Protocol.  */
    IPPORT_RJE = 77,
    IPPORT_FINGER = 79,   /* Finger service.  */
    IPPORT_TTYLINK = 87,
    IPPORT_SUPDUP = 95,   /* SUPDUP protocol.  */
    IPPORT_EXECSERVER = 512,  /* execd service.  */
    IPPORT_LOGINSERVER = 513, /* rlogind service.  */
    IPPORT_CMDSERVER = 514,
    IPPORT_EFSSERVER = 520,
    /* UDP ports.  */
    IPPORT_BIFFUDP = 512,
    IPPORT_WHOSERVER = 513,
    IPPORT_ROUTESERVER = 520,
    /* Ports less than this value are reserved for privileged processes.  */
    IPPORT_RESERVED = 1024,
    /* Ports greater this value are reserved for (non-privileged) servers.  */
    IPPORT_USERRESERVED = 5000


IPv6 套接字地址格式

struct sockaddr_in6
  {
    sa_family_t sin6_family; /* 16-bit */
    in_port_t sin6_port;  /* 传输端口号 # 16-bit */
    uint32_t sin6_flowinfo; /* IPv6流控信息 32-bit*/
    struct in6_addr sin6_addr;  /* IPv6地址128-bit */
    uint32_t sin6_scope_id; /* IPv6域ID 32-bit */
  };


IPv4 和 IPv6 套接字地址结构的长度是固定的,而本地地址结构的长度是可变的。

image.png

相关文章
|
缓存 监控 Linux
计算机网络编程 | 多路I/O转接服务器
计算机网络编程 | 多路I/O转接服务器
56 0
|
存储 网络协议 Unix
网络基础:socket套接字
网络基础:socket套接字
97 0
|
7月前
|
网络协议 Unix 开发者
套接字网络协议支持
套接字网络协议支持
38 1
|
7月前
|
机器学习/深度学习 监控 安全
计算机在通信领域的应用
计算机在通信领域的应用
|
网络协议 小程序 Java
网络编程之 Socket 套接字(使用数据报套接字和流套接字分别实现一个小程序(附源码))
1. 什么是网络编程 2. 网络编程中的基本概念 1)发送端和接收端 2)请求和响应 3)客户端和服务端 4)常见的客户端服务端模型 3. Socket 套接字 1)Socket 的分类 2)Java 数据报套接字通信模型 3)Java 流套接字通信模型 4. UDP 数据报套接字编程 1)DatagramSocket API 2)DatagramPacket API 3)示例 5. TCP 流套接字编程 1)ServerSocket API 2)Socket API 3)示例 a. 短连接版本 b. 长连接并发版本
280 0
|
存储 网络协议 算法
|
网络协议 索引
【网络】网络编程套接字(一)(2)
【网络】网络编程套接字(一)(1)
【网络】网络编程套接字(一)(2)
|
7月前
|
存储 网络协议 安全
网络编程『socket套接字 ‖ 简易UDP网络程序』
网络编程『socket套接字 ‖ 简易UDP网络程序』
125 0
|
存储 网络协议
|
存储 数据采集 网络协议
【网络】socket套接字编程
【网络】socket套接字编程