目录
3.1、TCP API接口(Berkeley Sockets)
1、Internet
互联网(Internet)是指一种全球性、开放的、基于分组 packet 交换的计算机网络,通过互联网,可以实现全球范围内的数据交换和通信
1.1、OSI模型
OSI模型(开放系统互联模型)是一个七层抽象模型,用于描述网络通信的各个层次及其相互作用。 每一层都有其特定的功能,并通过与相邻层进行交互来实现网络通信。从下到上,七层分别是:
-
物理层 (Physical Layer): 定义了网络设备之间物理连接的特性,例如电缆类型、电压、数据传输速率等。 关注的是比特的传输。
-
数据链路层 (Data Link Layer): 负责在相邻节点之间可靠地传输数据帧。 包括寻址、错误检测和纠正等功能,常用的协议有以太网。
-
网络层 (Network Layer): 负责在网络之间路由数据包,确定数据包的路径。 IP协议是该层的核心协议。
-
传输层 (Transport Layer): 提供端到端的可靠数据传输,负责数据的分割、重组、流量控制和错误检测。 TCP和UDP协议是该层的代表性协议。
-
会话层 (Session Layer): 负责建立、管理和终止两个应用程序之间的会话。 它提供了一种机制来同步和协调通信。
-
表示层 (Presentation Layer): 负责数据的格式转换和编码,确保不同系统之间的数据能够相互理解。 例如,字符编码转换。
-
应用层 (Application Layer): 直接为用户提供网络服务,例如HTTP、FTP、SMTP等协议都属于这一层。 用户使用的各种网络应用都运行在这一层。
每一层都封装了来自上层的数据,并将其传递给下层,最终到达物理层进行传输。 接收端则按照相反的顺序进行解封装,直到数据到达应用层。 这种分层结构使得网络的设计、维护和升级更加方便。
1.2、OSI模型图
1.3、TCP/IP协议族
TCP/IP协议族是一组网络协议,用于在互联网上进行数据传输。它并非单个协议,而是一组相互协作的协议的集合。 最主要的两个协议是TCP(传输控制协议)和IP(互联网协议)。
-
IP协议 (Internet Protocol): 负责数据的寻址和路由。它将数据包从源地址传递到目标地址,类似于邮递员负责将信件投递到正确的地址。IP协议是无连接的,不保证数据的可靠传输,可能会出现数据丢失或顺序错乱的情况。 IPv4和IPv6是IP协议的两个主要版本,IPv6是IPv4的升级,解决了IPv4地址空间不足的问题。
-
TCP协议 (Transmission Control Protocol): 负责数据的可靠传输。它在IP协议的基础上,提供面向连接、可靠、有序的数据传输服务。TCP协议会进行数据校验、流量控制、拥塞控制等,确保数据完整、有序地到达目的地。 你可以把它想象成快递服务,确保包裹安全送达,并提供追踪信息。
除了TCP和IP,TCP/IP协议族还包含许多其他协议,例如:UDP(用户数据报协议)、ICMP(互联网控制报文协议)、ARP(地址解析协议)、DHCP(动态主机配置协议)等等,这些协议协同工作,才能实现互联网的正常运作。 它们分别负责不同的功能,共同构成了互联网的通信基础。
1.4、TCP/IP协议族模型
1.5、 TCP/IP协议与OSI的对应
2、TCP与UDP
TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram Protocol,用户数据报协议)都是网络传输层协议,但它们在可靠性、效率和应用场景方面存在显著差异。
2.1、TCP
- 特点: 面向连接、可靠、有序、流控。 在数据传输前需要建立连接,确保数据完整性和顺序到达。它通过序号、确认、重传等机制来保证可靠性,并使用滑动窗口机制进行流量控制,避免网络拥塞。
- 可靠性: TCP提供端到端可靠的数据传输,保证数据不丢失、不重复、按序到达。
- 效率: 由于需要建立连接和进行各种校验,TCP的效率相对较低。
- 应用场景: 对可靠性要求高的应用,例如:Web浏览(HTTP)、电子邮件(SMTP)、文件传输(FTP)、远程登录(SSH)等。
2.2、UDP
- 特点: 面向无连接、不可靠、无序、无流控。 数据传输无需建立连接,直接发送数据包。它不保证数据的完整性和顺序到达,也不进行流量控制。
- 可靠性: UDP不提供可靠性保证,数据可能丢失、重复或乱序到达。
- 效率: 由于无需建立连接和进行各种校验,UDP的效率很高。
- 应用场景: 对实时性要求高、对可靠性要求低的应用,例如:在线游戏、视频直播、语音聊天、DNS查询等
2.3、TCP与UDP对比
2.4、 小结
选择TCP还是UDP取决于应用的需求。如果需要保证数据的可靠性,则选择TCP;如果需要保证数据的实时性,即使牺牲一些可靠性也在所不惜,则选择UDP。 很多应用也可能同时使用TCP和UDP,例如一些网络游戏可能使用UDP传输游戏数据,使用TCP传输聊天信息。
3、网络通信
结合前面学习的C语言——套接字以及C语言——文件IO,咱们就可以用TCP或者UDP网络协议开始进行网络编程了~
3.1、TCP API接口(Berkeley Sockets)
Berkeley Sockets (BSD sockets): 这是最常用的TCP API接口,被大多数Unix-like系统(如Linux、macOS、BSD)采用。 其核心函数包括:
socket()
: 创建一个套接字,指定协议族(AF_INET表示IPv4,AF_INET6表示IPv6)、套接字类型(SOCK_STREAM表示TCP,SOCK_DGRAM表示UDP)和协议(通常为0,由系统选择合适的协议)。bind()
: 将套接字绑定到一个特定的本地IP地址和端口号。listen()
: 对于服务器端,监听来自客户端的连接请求,指定最大等待连接数。accept()
: 对于服务器端,接受一个客户端的连接请求,返回一个新的套接字用于与该客户端通信。connect()
: 对于客户端,连接到服务器指定的IP地址和端口号。send()
/recv()
: 发送和接收数据。close()
: 关闭套接字。getsockopt()
/setsockopt()
: 获取和设置套接字选项,例如超时时间、缓冲区大小等。
3.2、服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[256];
// 创建服务器套接字
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("socket");
exit(1);
}
// 设置服务器套接字地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
// 绑定服务器套接字
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind");
exit(1);
}
// 监听客户端连接
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(1);
}
printf("Server started. Listening on port %d...", PORT);
while (1) {
// 接收客户端连接
client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);
if (client_fd < 0) {
perror("accept");
continue;
}
printf("Client connected. Address: %s:%d", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 处理客户端数据
while (1) {
int n = read(client_fd, buffer, 256);
if (n < 0) {
perror("read");
break;
} else if (n == 0) {
printf("Client disconnected.");
break;
}
printf("Received: %s", buffer);
write(client_fd, "Hello, client!", 13);
}
close(client_fd);
}
close(server_fd);
return 0;
}
3.3、客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080
int main() {
int client_fd;
struct sockaddr_in server_addr;
char buffer[256];
// 创建客户端套接字
client_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_fd < 0) {
perror("socket");
exit(1);
}
// 设置服务器套接字地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
// 连接服务器
if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("connect");
exit(1);
}
printf("Connected to server.");
// 发送数据
while (1) {
printf("Enter message: ");
fgets(buffer, 256, stdin);
write(client_fd, buffer, strlen(buffer));
// 接收服务器响应
read(client_fd, buffer, 256);
printf("Received: %s", buffer);
}
close(client_fd);
return 0;
}
3.4、释义
服务器端将监听端口8080,客户端将连接到服务器端,并发送数据。服务器端将接收客户端数据,处理数据,并将响应发送回客户端。
在write与read函数中输入自己想要传输的数据,就可以实现通信拉~
比如用来实现,服务器与客户端的聊天~
自己copy去尝试吧
有问题随时评论