【Socket编程预备知识】

网络通信的最终目的不是把数据扔给主机,而是把数据交给人正在使用的程序 ------QQ、浏览器、游戏客户端。

这些程序在操作系统中以进程 的形式存在。

所以,网络通信的本质 = 两个不同主机上的进程之间的通信

🧠 关键认知转变:

之前我们关心"主机到主机",现在开始关心"进程到进程"。

要让进程能收发网络数据,**操作系统提供了一套编程接口------Socket API。**而在使用它之前,必须先搞懂几个核心概念:IP地址、端口号、字节序等。


一、数据到底要传给谁?

明确:数据传输到主机是目的吗 ?

--> 不是,因为数据是给人使用的 。 进程是人在系统的代表 , 只要把数据给进程,人就相当于拿到了数据 。所以数据传输到主机不是目的,而是手段 。 到达主句内部 , 再交给主机内的进程,才是目的 。

  • 你用 QQ 发消息 → 数据要给 QQ 进程
  • 你打开网页 → 数据要给浏览器进程
  • 一台主机同时跑很多进程,必须有办法区分

所以网络通信的真正目标是:从「发送方进程」 → 传到「接收方进程」

但是 , 系统中 , 同时会存在非常多的进程 ,当数据到达目标主机后 , 怎么转发给目标进程 ??? 这就要在网络背景下,在系统中 , 标识主机的唯一性

二、认识端口号

2.1 源IP与目的IP:找到那台主机

IP地址 (如 192.168.0.1)的作用是在整个互联网中唯一标识一台主机

  • 源IP地址:数据从哪台主机发出来。

  • 目的IP地址:数据要送到哪台主机。

当你在浏览器里访问 www.baidu.com,DNS解析出百度服务器的IP地址(如 110.242.68.66),那么你发出的数据包中:

  • 源IP = 你电脑的公网IP

  • 目的IP = 110.242.68.66

🌰 小比喻:IP地址就像 省+市+街道+门牌号,能让你准确找到一栋大楼。

2.2 端口号

端口号(port)是传输层协议的内容

  • 传输层的概念
  • 2字节 , 16 位整数(0 ~ 65535)
  • 作用:标识主机里的一个进程

一句话:IP 找到哪台主机,端口找到哪个程序。

要点:

  • 一个进程可以绑定多个端口
  • 一个端口只能被一个进程占用

IP + port 能够便是网络上的某一台主机的某一个进程

2.3 端口范围划分

范围 分类 说明
0 ~ 1023 知名端口号 系统预留,给标准服务:HTTP=80,HTTPS=443,SSH=22,FTP=21
1024 ~ 65535 动态/私有端口号 操作系统动态分配给客户端程序,比如你的QQ、Chrome

🌰 小比喻:

  • 主机 = 一栋写字楼

  • 端口号 = 楼层+房间号

  • 知名端口 = 星巴克(总在一楼)、顺丰快递点(固定位置)

2.4 端口号 vs 进程ID(PID)

你可能会问:操作系统里每个进程都有唯一的PID,为什么不用PID来代替端口号?

对比项 端口号 PID
范围 0~65535,网络约定 系统动态分配,可能很大
变化 相对稳定(服务固定端口) 每次启动都变
耦合性 网络标准,与系统解耦 强依赖特定操作系统实现
多对一 一个进程可绑定多个端口 一个进程只有一个PID
一对多 一个端口只能被一个进程占用 不适用

核心原因 :PID是操作系统内部概念,而网络通信需要跨平台、跨系统。如果强绑PID,那么Windows和Linux的PID管理方式不同,无法互通。

端口号是TCP/IP协议栈的一部分,独立于操作系统。

另外,一个进程可以同时监听多个端口(比如一个Web服务器同时监听80和443),而一个端口只能被一个进程占用。

简要总结:

  • PID:操作系统内部标识进程
  • Port:网络层面标识进程
  • 为什么不用 PID?会让网络与系统强耦合,所以专门设计端口号

2.5 源端口与目的端口:谁发的,发给谁

传输层协议(TCP/UDP)的报文头中,有两个关键的字段:

  • 源端口号:发送方进程绑定的端口

  • 目的端口号:接收方进程绑定的端口

就是在描述 "数据是谁发的,要发给谁 "

这样,对方回复时,就知道把数据回给哪个进程

复制代码
例如:你的QQ(端口 12345) 发送消息 → 腾讯服务器(端口 80)
数据包中:
  源IP = 你的IP,源端口 = 12345
目的IP = 服务器IP,目的端口 = 80

服务器处理完后,回复给你的QQ时,会把源端口和目的端口交换:

  • 源IP = 服务器IP,源端口 = 80

  • 目的IP = 你的IP,目的端口 = 12345

🌰 小比喻:

  • 你写信给"上海XX公司 财务部 收"(目的端口=财务部)

  • 落款写"北京YY小区 张三 寄"(源端口=张三)

  • 对方回信时,写"北京YY小区 张三 收"(目的端口指向你),落款"上海XX公司 财务部"(源端口不变)

三、理解socket

Socket = IP 地址 + 端口号 --》 唯一标识一个网络进程

1. 把IP地址和端口号组合起来,就能在整个互联网中唯一标识一个进程

这个组合,就叫 Socket(套接字)

  1. 网络通信本质上就是两个socket之间的对话。

  2. 更进一步,一个完整的网络连接由四元组唯一确定:

    { 源IP, 源端口, 目的IP, 目的端口 }

  1. 所以,网络通信的本质,也是进程间通信

网络通信的本质是进程间通信(IPC)

我们之前学过的进程间通信(管道、消息队列、共享内存)都在同一台主机 上。

网络通信 ,就是跨主机的进程间通信------只不过借助了网络协议栈。

🧠 这一点非常重要:socket编程,本质就是在写一个能跟另一台机器上的进程"说话"的程序。

四、传输层的典型代表

4.1 TCP(传输控制协议)

  • 有连接
  • 可靠传输
  • 面向字节流
  • 像:打电话(先接通再说话)

4.2 UDP(用户数据报协议)

  • 无连接
  • 不可靠
  • 面向数据报
  • 像:寄信(直接扔邮箱,不管收没收到)

这部分先记特点,后面深入学。

特性 TCP UDP
全名 传输控制协议 用户数据报协议
连接 有连接(先打电话,再说话) 无连接(直接扔包裹,不管收到没)
可靠性 可靠传输(确认、重传、排序) 不可靠传输(丢了不重发,顺序可能乱)
传输方式 面向字节流(像水管,无边界) 面向数据报(一个个独立包,有边界)
速度 较慢(因为可靠性开销) 较快
典型应用 HTTP、HTTPS、FTP、SSH、大部分文件下载 视频直播、DNS查询、网络游戏(部分)

五、网络字节序

5.1 什么是字节序?

对于一个多字节整数(比如 0x12345678),在内存中存储有两种方式:

  • 大端(Big-Endian):高位字节存在低地址。例如 0x12 在低地址。

  • **小端(Little-Endian):****低位字节存在低地址。**例如 0x78 在低地址。

我们的x86 PC是小端 的,而很多网络设备、ARM等可能是大端的。

如果不做转换,直接发送内存中的整数,对方会解析错。

5.2 TCP/IP规定:网络字节序 = 大端

为了保证所有设备都能正确解析,发送前,主机字节序 要转为网络字节序(大端);接收后,再转回主机字节序。

操作系统提供了四个便捷函数:

函数 含义
htonl() Host to Network Long (32位整数转换)
htons() Host to Network Short (16位整数转换)
ntohl() Network to Host Long
ntohs() Network to Host Short

h:host(主机)

n:network(网络)

s:short(16 位,端口)

l:long(32 位,IP)

🌰 小比喻:

你和英国人交流,要先把中文(小端)翻译成英文(大端),收到英文回复后再翻译回中文。

在编程中,IP地址(32位整数)和端口号(16位整数) 都需要用这些函数进行转换,然后再填充到socket地址结构中。

六、socket编程接口速览

下面的C语言接口是POSIX标准,几乎所有操作系统都支持。

复制代码
// 1. 创建socket描述符(类似打开文件)
int socket(int domain, int type, int protocol);

// 2. 绑定端口和IP(服务器必须做)
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

// 3. 监听连接(TCP服务器)
int listen(int sockfd, int backlog);

// 4. 接受连接(TCP服务器)
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

// 5. 建立连接(TCP客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

sockaddr结构:通用地址

为了支持IPv4、IPv6、Unix域套接字等不同地址格式,socket API使用一个"通用"结构 struct sockaddr

复制代码
struct sockaddr {
    sa_family_t sa_family;   // 地址类型,如 AF_INET
    char        sa_data[14]; // 地址数据(IP、端口等)
};

实际编程中,我们使用 IPv4专用结构 sockaddr_in:

复制代码
struct sockaddr_in {
    sa_family_t    sin_family;   // AF_INET
    in_port_t      sin_port;     // 端口号(网络字节序)
    struct in_addr sin_addr;     // IP地址(网络字节序)
};

其中 in_addr 就是一个32位整数:

复制代码
struct in_addr {
    in_addr_t s_addr;   // 32位IP地址
};

为什么需要sockaddr?

因为API要统一处理多种协议族的地址,所以设计了一个抽象类型 sockaddr*

使用时,你把 sockaddr_in 结构体的指针强制转换(struct sockaddr*) 传给函数,函数内部根据 sin_family 字段判断是哪种地址类型。

🌰 小比喻:
sockaddr 就像"包裹"的通用标签,里面写着包裹类型(是快递信、还是生鲜、还是文件)。

真正寄快递时,你会用一个具体的盒子(sockaddr_in)去包装,然后告诉快递员"我这是一个通用包裹"(强制转型)。

相关推荐
用户9718356334665 小时前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪6 小时前
linux 拷贝文件或目录到指定的位置
linux
大树881 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠1 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质1 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush41 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5201 天前
Linux 11 动态监控指令top
linux
小宇宙Zz1 天前
Maven依赖冲突
java·服务器·maven
Inhand陈工1 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
网络研究院1 天前
2026年网络安全
网络·安全·法律·法规·趋势·发展