关注

【Linux网络】网络通信:Socket编程入门


1 ~> 网络通信的本质

网络通信的本质就是两个主机的进程之间在通信,网络就是两个进程看到的同一份资源。即两个进程通过网络进行数据交互:从远端获取数据和将数据发送到远端。
那么要能够通信就需要:

  • 主机A要能够找到主机B;
  • 进程A要能够找到进程B。

2~> 理解源IP地址和目的IP地址

IP在网络中,用来标识唯一的一台主机。
源 IP 地址:标识数据包的发送方主机。
目的 IP 地址:标识数据包的接收方主机。
在这里插入图片描述
通过局部到整体,数据包由主机A交到主机B,但最终还需要将数据交给进程处理。但一个主机中有非常多的进程,所以,就需要对目标进程进行标记。
在这里插入图片描述

3~> 认识端口号Port

端口号是一个2字节的16位整数,用来标识一台主机中唯一的进程。

3.1 端口号的范围划分

  • 0 ~ 1023:系统端口/知名端口,HTTP, FTP, SSH 等这些广为使用的应用层协议, 他们的端口号都是固定的。即约定这些端口号为特定的服务所占用,方便客户端同一访问,如报警打110。
  • 1024 - 65535 :操作系统动态分配的端口号。客户端程序的端口号, 就是由操作系统从这个范围分配的。未来我们在进行套接字通信时指定的端口就在这个范围。

注意: 一个进程可以绑定多个端口号,但一个端口号只能被一个进程绑定!

3.2 理解socket

IP标识唯一的主机,端口号标识主机上唯一的进程。
那么 IP + Port即对应互联网中唯一的进程,即套接字。通过套接字,主机A上的进程A就能够把数据准确交给主机B上的进程B了。

3.3 端口号和进程PID

当我们创建一个进程,操作系统会自动为进程分配PID,PID标识唯一的进程。那为什么不直接用IP + PID?
首先,PID是系统概念,这样不符合解耦设计的分层哲学;其次,端口号将来需要被客户端明确知道,而端口号由客户端自己约定比较方便。
更何况不是所有进程都需要网络通信!

4 ~> 网络字节序

所有在网络中传输的多字节数据,必须使用大端序编码,这称为"网络字节序"。

4.1 为什么要规定网络字节序?

计算机存储多字节数据有两种顺序:例如存储(0x12345678

  • 大端存储:高字节位放在低地址处,即12 34 56 78,符合我们的阅读习惯。
  • 小端存储:高字节位存储在该地址处,即78 56 34 12

假如主机A(大端)想要将0x12345678发送给主机B(小端),最终主机B存的将是12 34 56 78,刚好相反。
所以,就需要一个标准,规定发送到网络中的必须是大端序列。大端机器正常读,小端机器在读之前先将大端 -> 小端即可。

4.2 网络字节序转化

主机将数据发送到网络,必须先转化为大端序:

  • htons(Host to Network Short):将端口号转化为网络字节序
  • htonl(Host to Network Long):将IP转化为网络字节序

从网络读取的数据,必须转化为自身序列:

  • ntohs:将端口号由网络字节序转为主机序列
  • ntohl:将IP由网络字节序转为主机序列

5 ~> Socket编程接口

Socket接口是应用层进入传输层的入口,即用户层通过系统调用(API)触发用户态与内核态之间的数据拷贝,从而间接完成网络数据的收发。

5.1 相关API介绍

(1)创建套接字(TCP/UDP,服务端+客户端)

int socket(int domain, int type, int protocol);
参数含义常用取值
domain协议族/地址族AF_INET (IPv4)、AF_INET6 (IPv6)、AF_UNIX (本地套接字)
type套接字类型SOCK_STREAM (TCP)、SOCK_DGRAM (UDP)、SOCK_RAW (原始套接字)
protocol具体协议:通常填 0,让系统根据 domain+type 自动选择IPPROTO_TCPIPPROTO_UDPIPPROTO_ICMP

domain 协议族:

取值说明
AF_INETIPv4 地址,使用 sockaddr_in 结构体,地址是 32 位
AF_INET6IPv6 地址,使用 sockaddr_in6 结构体,地址是 128 位

type:套接字类型

取值说明对应协议
SOCK_STREAM面向连接、可靠、字节流、有序、无边界TCP
SOCK_DGRAM无连接、不可靠、数据报、有边界、可能乱序/丢失UDP
// ------------------代码示例-------------------------
// 创建一个 TCP/IPv4 套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);

// 创建一个 UDP/IPv4 套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

(2)绑定(TCP/UDP,服务端)
它把一个具体的地址(IP + 端口)绑定到套接字上,告诉操作系统:"这个端口归我管,有数据来就交给我。

int bind(int socket, const struct sockaddr *address, socklen_t address_len);
参数类型作用
sockfdintsocket() 创建的套接字文件描述符
addrconst struct sockaddr *指向地址结构体的指针(包含 IP + 端口)
addrlensocklen_taddr 指向结构体的实际字节长度

(3)监听(TCP,服务端)

int listen(int socket, int backlog);

如果创建套接字和绑定是开饭馆和挂牌子,那么listen就是让饭馆开始营业,backlog代表饭馆能坐多少桌。所以只有监听后(即套接字处于listen状态)才能够接收数据,并放入队列等待处理。

(4)接收请求(TCP,服务端)

int accept(int socket, struct sockaddr* address, socklen_t* address_len);

服务端阻塞等待,当客户端发起连接connect,此时客户端accept接受请求,并返回一个全新的套接字描述符,专门用于与这个客户端通信。
address为输出型参数,存储了客户端的IP + Port
(5)建立连接(TCP, 客户端)

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

向服务器发起连接,addr存储了要连接的服务端的IP + Port

5.2 结构体家族

  • sockaddr结构体——基类
struct sockaddr 
{
    sa_family_t sa_family;  // 地址族(如 AF_INET)
    char        sa_data[14]; // 存储具体地址数据(但空间不够,只是个占位符)
};
  • sockaddr_in结构体——真正的 IPv4“身份证”

包含了IP和Port信息,就可以与对应进程进行数据交互。

struct sockaddr_in 
{
    sa_family_t    sin_family;   // 必须填 AF_INET
    in_port_t      sin_port;     // 端口号(必须 htons 转换)
    struct in_addr sin_addr;     // IP 地址(必须 htonl 或 inet_pton 转换)
    char           sin_zero[8];  // 填充位,保证总长度与 sockaddr 一致
};

struct in_addr 
{
    in_addr_t s_addr;   // 真正的IP
};
  • sockaddr_un结构体——本地通信的“身份证”
struct sockaddr_un {
    sa_family_t sun_family;      // 必须填 AF_UNIX
    char        sun_path[108];   // 套接字文件的路径(如 "/tmp/my.sock")
};

struct sockaddr *address 是基类指针,使用sockaddr_in和sockaddr_un时需要强转。

5.2 传输层协议 UDP和TCP

5.2.1 认识UDP协议

  • 无连接
  • 不可靠传输
  • 面向数据报

UDP通信流程:
在这里插入图片描述

  • 客户端不需要 bind()(系统自动分配临时端口)

  • 数据报之间相互独立,可能丢包、乱序

5.2.2 认识TCP协议

  • 有连接
  • 可靠传输
  • 面向字节流

在这里插入图片描述

  • 服务端必须 bind + listen + accept 三步曲

  • 客户端必须 connect 主动建立连接。

  • accept() 返回的新套接字用于通信,原监听套接字继续等新连接。

  • TCP 是字节流,无消息边界,需要应用层自行处理。

6 ~> 总结

网络编程的核心是跨主机的进程间通信,IP + Port 标识两个唯一的进程,通过 TCP/IP 协议栈完成数据交换。
理论准备完成,那么我们就可以接着进行网络通信实战了!

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/Miun123/article/details/162933425

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--