一、共享内存
共享内存是通过映射的方式在内核中申请一段可以使用的物理内存空间来映射到用户空间中,用户对用户空间的操作就是直接操作物理内存区域。通过这种方式,进程可以直接读写这部分内存,从而实现高效的数据交换。相比于其他 IPC 机制(如管道、消息队列、套接字等),共享内存的优点在于它提供了更快的数据传输速度,因为数据不需要通过内核进行复制。
特点:
- 共享内存是所有 IPC 机制中效率最高的一种,因为它允许多个进程直接访问同一块内存区域,避免了数据复制的开销。
使用步骤:
1.创建key值:
ftok函数
ftok
是一个用于生成唯一键的函数,通常在 IPC(进程间通信)机制中使用。它的主要作用是从一个给定的路径名和一个项目 ID(通常是一个整型值)生成一个唯一的键值,以便在不同的进程中访问同一IPC资源
key_t ftok(const char *pathname, int proj_id);
- pathname: 一个指向文件路径的字符串,要求该文件必须存在于文件系统中。这个文件用来确保生成的键在多个进程中保持唯一性。
- proj_id: 一个项目标识符 (Project Identifier)。它是一个整数值,(最低八位有效) 通常可以取值0到255,用于区分同一文件生成的不同键。(通常可以设置为一个字符‘A’)
返回值:
- 如果成功,
ftok
返回一个唯一的键值(key_t
类型)。 - 如果失败,则返回
-1
,并且设置errno
来指示错误原因。
2.创建或获取一个共享内存段:
shmget函数
-
功能:创建一个共享内存段或获取一个已经存在的共享内存段。
int shmget(key_t key, size_t size, int shmflg);
-
key
: 唯一标识符,用于标识共享内存段。 -
size
: 要创建的共享内存段的大小(以字节为单位)。 -
shmflg
: 权限标志,包括 IPC_CREAT(如果共享内存段不存在则创建),以及权限(如 0666)。
-
返回值:成功时返回共享内存标识符,失败时返回 -1。
3. 绑定(映射)本地内存和共享内存:
shmat函数
void* shmat(int shmid, const void* shmaddr, int shmflg):
-
shmid
: 由shmget()
返回的共享内存标识符。 -
shmaddr
: 指定的附加地址,通常为 NULL(由系统选择地址)。 -
shmflg
: 附加标志,通常为 0。
-
返回值:成功时返回共享内存的指针,失败时返回 (void*) -1。
4.解绑本地内存和共享内存
shmdt函数:将绑定到进程地址空间的共享内存段分离
int shmdt(const void* shmaddr)
hmaddr
: 指向要分离的共享内存的指针。
返回值:成功时返回 0,失败时返回 -1
5.删除共享内存:
shmctl函数:
-
操作共享内存段的控制信息,或删除共享内存。
int shmctl(int shmid, int cmd, struct shmid_ds* buf)
-
shmid
: 共享内存标识符。 -
cmd
: 操作命令,常用的包括 IPC_RMID(删除共享内存段)和 IPC_STAT(获取共享内存段信息)。 -
buf
: 指向共享内存段属性的结构体,用于 IPC_STAT 和 IPC_SET 等。 -
返回值:成功时返回 0,失败时返回 -1。
二、网络基础
1.网络体系结构
TCP/IP四层协议栈:
网络接口层:负责物理传输介质上的数据传输
网际层:处理数据包在不同网络之间的路由和传输。
传输层:提供端到端的通信服务,确保数据的完整性、顺序性以及正确传输。它管理数据流的分段、传输和重组。
应用层::负责处理特定的应用服务,直接与用户交互。
TCP/IP五层协议栈:
将网络接口层详细划分为物理层和数据链路层,增加了一个独立的物理层,使得它更接近于OSI(开放系统互联)七层模型。
2.IPv4地址
1. 基本结构
- 长度:IPv4地址是一个32位的二进制数,通常以点分十进制表示,由四个十进制数构成,每个数占8位,取值范围是0到255。比如:
192.168.1.1
。 - 表示形式:点分十进制,如
192.168.0.1
。 - 地址范围:每个IPv4地址的数值范围是
0.0.0.0
到255.255.255.255
。
2. 分类
- IPv4地址被分为5类(A类、B类、C类、D类、E类),其中A、B、C类地址用于主机标识,D类用于组播,E类保留用于实验。
类别 | 起始地址范围 | 子网掩码默认长度 | 用途 |
---|---|---|---|
A | 0.0.0.0 – 127.255.255.255 | /8 | 大型网络 |
B | 128.0.0.0 – 191.255.255.255 | /16 | 中型网络 |
C | 192.0.0.0 – 223.255.255.255 | /24 | 小型网络 |
D | 224.0.0.0 – 239.255.255.255 | 组播地址 | |
E | 240.0.0.0 – 255.255.255.255 | 实验和保留地址 |
3. 特殊地址
- 私有地址(Private IP):不用于互联网,专用于局域网内部通信。
- A类私有地址:
10.0.0.0 - 10.255.255.255
- B类私有地址:
172.16.0.0 - 172.31.255.255
- C类私有地址:
192.168.0.0 - 192.168.255.255
- A类私有地址:
- 回环地址(Loopback Address):
127.0.0.0 - 127.255.255.255
,主要用于主机内部通信,最常用的是127.0.0.1
。 - 广播地址(Broadcast Address):用于向网络中所有设备发送信息,例如
192.168.1.255
。
4. 子网划分
- 子网掩码(Subnet Mask):用于区分IP地址中的网络部分和主机部分。子网掩码与IP地址相结合,可以确定一个特定的子网范围。常见的子网掩码形式是:
255.255.255.0
。
3.TCP/UDP
TCP(Transmission Control Protocol)和 UDP(User Datagram Protocol)是传输层的两种主要协议。
TCP的特点:
-
面向连接 :TCP是面向连接的协议,在传输数据之前需要建立一个连接并在传输完成后关闭连接。
-
可靠性:通过各种机制来确保所有数据包都能正确送达。
-
有序性:TCP保证数据按发送顺序到达接收方。它使用序列号来跟踪数据包的顺序,即使数据包在传输过程中到达的顺序不同,TCP也会按正确顺序重新组装。
UDP的特点:
-
无连接:UDP是无连接的协议,不需要在传输数据之前建立连接。它直接发送数据包(称为数据报)到目标地址,不需要确认连接状态。
-
不可靠性:UDP不保证数据包的送达,不会对丢失的、损坏的或乱序的数据包进行重传或纠正。如果数据包在传输过程中丢失或损坏,UDP也不会通知发送方。
-
无序性 :UDP不保证数据包按顺序到达接收方。每个数据包独立传输,接收方收到数据包的顺序可能与发送顺序不同。
总结:
- TCP 强调可靠性、有序性和流量控制,适合对数据传输要求严格的应用。
- UDP 则更注重速度和低延迟,适合对实时性要求高而对可靠性要求较低的应用。
三、网络编程
基本的通信模式:
c/s :client/server 客户端/服务器模式 ------------ 专用客户端
b/s :brower/server 浏览器/服务器模式 ---------- 通用客户端
p2p 点到点的模式
1. Socket函数:
-
int socket(int domain, int type, int protocol);
- 作用:创建一个新的套接字。
- 参数:
domain
:指定协议族,如AF_INET
(IPv4)、AF_INET6
(IPv6)。type
:指定套接字类型,如SOCK_STREAM
(TCP)、SOCK_DGRAM
(UDP)。protocol
:通常设为 0,表示使用默认协议(TCP或UDP)。
- 返回值:成功时返回套接字描述符,失败时返回
-1
。
2. Sendto函数:
-
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
- 作用:向套接字发送数据。
sendto
适用于UDP。 - 参数:
sockfd
:套接字描述符。buf
:指向要发送的数据缓冲区。len
:数据长度。flags
:指定发送行为的标志,一般设为 0。dest_addr
和addrlen
:指定目标地址(用于UDP)。
- 返回值:成功时返回发送的字节数,失败时返回
-1
。
char buf[1024] = "hello udp\n";
struct sockaddr_in seraddr;
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(50000); //网络端口号使用的是大端模式,因此要通过htons函数将小端存储的数转换为大端模式
seraddr.sin_addr.s_addr = inet_addr("192.168.1.149"); // ip
sendto(fd,buf,strlen(buf)+1,0,(const struct sockaddr *)&seraddr,sizeof(seraddr));