理解Socket(套接字)和地址


可以将Socket理解为电话,地址理解为电话号码

客户端和服务端核心逻辑

网络编程中,客户端和服务端的核心逻辑如下:
在这里插入图片描述

  • 服务器初始化
    • 初始化Socket
    • bind监听地址和端口
    • listen将原先的Socket转换为服务端的Socket
    • 服务端阻塞在accept上,等待客户端的请求
  • 客户端初始化
    • 初始化Socket
    • connect向服务端的地址和端口发起请求,进行TCP三次握手,建立连接
  • 数据传输过程
    • 客户端向操作系统内核发起write字节流写操作
    • 内核协议栈将字节流通过网络设备传到服务器端
    • 服务器端从内核得到信息,将字节流从内核读入进程中,并开始业务逻辑的处理
    • 完成之后,以同样的逻辑写给客户端
  • 关闭
    • 客户端执行Close操作,给服务端发FIN包
    • 服务端收到之后被动执行关闭,处理半关闭状态
    • 服务端执行Close,整个链路关闭

关闭和半关闭

  • 半关闭的状态,发起 close 请求的一方在没有收到对方 FIN 包之前都认为连接是正常的
  • 全关闭的状态,双方都感知连接已经关闭。

连接之后,数据的传输就不再是单向的,而是双向的,这是TCP的显著特征

客户端的connect、服务端的accept、read/write操作等都是Socket完成的,Socket是用来建立连接,传输数据的唯一路径。

Socket是什么

可以将TCP的网络交互和数据传输想象成打电话,整个类比如下:

  • Socket 类比为电话机
  • bind 类比为电信公司开户,绑定自家电话号码
  • listen类比听到铃声
  • accept类比被叫的一方拿起电话开始应答
  • connect 类比拨号
  • write 类比拨打电话的人说话
  • read 类比接听电话的人听的过程
  • 拨打电话的人挂掉电话,类比为客户端close
  • 接听电话的人也挂掉电话,类比为服务端close

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

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 */
  }; 

在这个结构体里,第一个字段是地址族,它表示使用什么样的方式对地址进行解释和保存,比电话簿里的手机格式,或者是固话格式

  • 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];
  };
  • 16-bit 的 sin_family 字段,和 sockaddr 一样,对于 IPv4 来说这个值就是 AF_INET。
  • 端口号,我们可以看到端口号最多是 16-bit,也就是说最大支持 2 的 16 次方,所以支持寻址的端口号最多就是 65535。关于所谓保留端口就是大家约定俗成的,已经被对应服务广为使用的端口,比如 ftp 的 21 端口,ssh 的 22 端口,http 的 80 端口等。一般而言,大于 5000 的端口可以作为我们自己应用程序的端口使用。
  • 实际的 IPv4 地址是一个 32-bit 的字段,可以想象最多支持的地址数就是 2 的 32 次方,大约是 42 亿,目前这个数字渐渐显得不太够用了,于是就有了 IPv6
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 */
  };

整个结构体长度是 28 个字节,其中流控信息和域 IP 先不用管,这两个字段,一个在 glibc 的官网上根本没出现,另一个是当前未使用的字段。

这里的地址族显然应该是 AF_INET6,端口同 IPv4 地址一样
地址从 32 位升级到 128 位,这个数字就大到恐怖了,完全解决了寻址数字不够的问题。

本地套接字地址格式
struct sockaddr_un {
    unsigned short sun_family; /* 固定为 AF_LOCAL */
    char sun_path[108];   /* 路径名 */
};
几种不同的套接字地址格式比较

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值