IT评测·应用市场-qidao123.com技术社区
标题:
TCP/UDP与线程进程全解析:从原理到实战
[打印本页]
作者:
天空闲话
时间:
7 天前
标题:
TCP/UDP与线程进程全解析:从原理到实战
TCP/UDP与线程进程全解析:从原理到实战
一、TCP与UDP协议深度解析
1. TCP协议详解
TCP(传输控制协议)是一种面向毗连的、可靠的、基于字节流的传输层通讯协议,是互联网的焦点协议之一。
焦点特性
:
面向毗连
:通过三次握手建立毗连,四次挥手断开毗连
可靠性保证
:通过确认应答、超时重传、数据排序等机制确保数据可靠传输
流量控制
:使用滑动窗口机制动态调解发送速率
拥塞控制
:通过慢启动、拥塞制止等算法防止网络过载
TCP头部布局
:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源端口号 | 目的端口号 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 序列号 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 确认应答号 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据偏移 | 保留 | 控制标志 | 窗口大小 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 校验和 | 紧急指针 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 选项(可选) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据(可选) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
复制代码
TCP三次握手过程
:
客户端发送SYN=1, seq=x
服务端回复SYN=1, ACK=1, seq=y, ack=x+1
客户端发送ACK=1, seq=x+1, ack=y+1
TCP四次挥手过程
:
自动方发送FIN=1, seq=u
被动方回复ACK=1, ack=u+1
被动方发送FIN=1, seq=v, ACK=1, ack=u+1
自动方回复ACK=1, seq=u+1, ack=v+1
2. UDP协议详解
UDP(用户数据报协议)是一种无毗连的、不可靠的传输层协议,提供简单高效的数据传输服务。
焦点特性
:
无毗连
:无需建立毗连即可发送数据
不可靠
:不保证数据到达、不保证顺序
轻量级
:头部开销小(仅8字节)
无流量控制
:发送速率完全由应用层控制
UDP头部布局
:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源端口号 | 目的端口号 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 长度 | 校验和 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据(如果有) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
复制代码
3. TCP与UDP对比
特性TCPUDP毗连性面向毗连无毗连可靠性可靠传输不可靠传输顺序保证保证数据顺序不保证顺序流量控制有无拥塞控制有无头部大小20-60字节8字节传输服从较低较高适用场景文件传输、网页浏览、邮件视频会议、在线游戏、DNS查询
二、线程与进程深度解析
1. 进程详解
进程定义
:
进程是操作系统资源分配的基本单位,是步伐的一次实行实例。每个进程都有独立的地址空间、文件描述符、环境变量等系统资源。
进程特点
:
独立性
:进程间相互隔离,一个进程崩溃不会影响其他进程
资源开销大
:创建和切换进程须要较大的系统开销
通讯复杂
:进程间通讯(IPC)须要特殊机制(管道、消息队列、共享内存等)
进程状态转换
:
新建 → 就绪 ↔ 运行 → 终止
↑ ↓
└── 阻塞
复制代码
2. 线程详解
线程定义
:
线程是CPU调度的基本单位,是进程内的一个实行流。同一进程内的多个线程共享进程的资源,但每个线程有自己的栈和寄存器状态。
线程特点
:
轻量级
:创建和切换线程的开销远小于进程
共享资源
:同一进程的线程共享内存空间和文件描述符等
通讯简单
:线程间可以直接通过共享内存通讯
缺乏掩护
:一个线程崩溃大概导致整个进程崩溃
线程状态转换
:
与进程类似,但通常更频仍地在就绪和运行状态间切换
3. 多线程与多进程对比
特性多进程多线程创建开销大小切换开销大小内存隔离完全隔离共享地址空间通讯方式IPC机制共享内存安全性高(一个进程崩溃不影响其他)低(一个线程崩溃大概导致整个进程崩溃)适用场景CPU麋集型、须要高隔离性I/O麋集型、须要高并发
三、实战案例解析
1. TCP服务器/客户端实现(C语言)
TCP服务器代码
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = {0};
// 创建socket文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置socket选项
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 绑定socket到端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);
// 接受连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
// 读取客户端数据
int valread = read(new_socket, buffer, BUFFER_SIZE);
printf("Received: %s\n", buffer);
// 发送响应
char *response = "Hello from server";
send(new_socket, response, strlen(response), 0);
printf("Response sent\n");
close(new_socket);
close(server_fd);
return 0;
}
复制代码
TCP客户端代码
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char buffer[BUFFER_SIZE] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// 转换IP地址
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
printf("\nInvalid address/ Address not supported \n");
return -1;
}
// 连接服务器
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\nConnection Failed \n");
return -1;
}
// 发送消息
char *message = "Hello from client";
send(sock, message, strlen(message), 0);
printf("Message sent\n");
// 读取响应
int valread = read(sock, buffer, BUFFER_SIZE);
printf("Server response: %s\n", buffer);
close(sock);
return 0;
}
复制代码
2. UDP服务器/客户端实现(C语言)
UDP服务器代码
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sockfd;
struct sockaddr_in servaddr, cliaddr;
char buffer[BUFFER_SIZE];
// 创建UDP socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// 绑定socket
if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("UDP Server listening on port %d...\n", PORT);
socklen_t len;
int n;
len = sizeof(cliaddr);
// 接收数据
n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr *)&cliaddr, &len);
buffer[n] = '\0';
printf("Client : %s\n", buffer);
// 发送响应
char *response = "Hello from UDP server";
sendto(sockfd, response, strlen(response), MSG_CONFIRM, (const struct sockaddr *)&cliaddr, len);
printf("Response sent.\n");
close(sockfd);
return 0;
}
复制代码
UDP客户端代码
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sockfd;
struct sockaddr_in servaddr;
char buffer[BUFFER_SIZE];
// 创建UDP socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = INADDR_ANY;
socklen_t len;
// 发送消息
char *message = "Hello from UDP client";
sendto(sockfd, message, strlen(message), MSG_CONFIRM, (const struct sockaddr *)&servaddr, sizeof(servaddr));
printf("Message sent.\n");
// 接收响应
int n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr *)&servaddr, &len);
buffer[n] = '\0';
printf("Server : %s\n", buffer);
close(sockfd);
return 0;
}
复制代码
3. 多线程服务器实现(C语言)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8080
#define BUFFER_SIZE 1024
#define MAX_CLIENTS 10
void *handle_client(void *arg) {
int client_socket = *(int *)arg;
char buffer[BUFFER_SIZE] = {0};
// 读取客户端数据
int valread = read(client_socket, buffer, BUFFER_SIZE);
printf("Thread %lu received: %s\n", pthread_self(), buffer);
// 发送响应
char *response = "Hello from server thread";
send(client_socket, response, strlen(response), 0);
close(client_socket);
free(arg);
return NULL;
}
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// 创建socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置socket选项
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 绑定socket
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听
if (listen(server_fd, MAX_CLIENTS) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("Multi-threaded server listening on port %d...\n", PORT);
while (1) {
int *client_socket = malloc(sizeof(int));
if ((*client_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
continue;
}
printf("New client connected\n");
// 创建线程处理客户端
pthread_t thread_id;
if (pthread_create(&thread_id, NULL, handle_client, client_socket) != 0) {
perror("pthread_create");
close(*client_socket);
free(client_socket);
}
// 分离线程,使其结束后自动释放资源
pthread_detach(thread_id);
}
close(server_fd);
return 0;
}
复制代码
四、性能优化与最佳实践
1. TCP/UDP性能优化
TCP优化技巧
:
调解TCP窗口大小以适应高耽误网络
启用TCP快速打开(TFO)减少握手耽误
使用TCP_NODELAY选项禁用Nagle算法(适用于及时应用)
合理设置SO_KEEPALIVE选项检测死毗连
使用毗连池减少频仍建立毗连的开销
UDP优化技巧
:
实现应用层的可靠传输机制(如QUIC协议)
添加序列号和确认机制处置处罚丢包
实现流量控制防止发送方压垮接收方
使用前向纠错(FEC)技能减少重传
合理设置缓冲区大小平衡耽误和吞吐量
2. 多线程编程最佳实践
线程安全设计
:
尽量减少共享数据
使用互斥锁掩护共享资源
制止死锁(按固定顺序获取锁)
使用读写锁优化读多写少场景
性能优化
:
合理设置线程池大小(CPU麋集型任务≈CPU焦点数,I/O麋集型任务可更多)
使用无锁数据布局减少锁竞争
使用线程局部存储(TLS)减少同步开销
批量处置处罚任务减少线程切换
错误处置处罚
:
准确处置处罚线程返回值
设置线程取消点
实现优雅退出机制
五、常见标题与办理方案
1. TCP粘包标题
标题描述
:TCP是字节流协议,不维护消息边界,大概导致多条消息粘在一起。
办理方案
:
固定长度消息
特殊分隔符(如换行符)
消息头+消息体格式(头中包罗消息长度)
2. UDP丢包标题
标题描述
:UDP不保证可靠传输,网络拥塞时大概出现丢包。
办理方案
:
应用层实现确认和重传机制
添加前向纠错(FEC)数据
使用更可靠的协议如QUIC
3. 多线程竞争条件
标题描述
:多个线程同时访问共享资源导致数据不一致。
办理方案
:
使用互斥锁掩护临界区
使用原子操作
设计为无锁算法
六、总结
TCP和UDP作为传输层两大协议各有优劣:TCP提供可靠传输但开销较大,UDP轻量高效但不保证可靠性。线程和进程作为并发编程的两大模型也各有适用场景:多进程隔离性好但开销大,多线程轻量但须要谨慎处置处罚共享数据。
在现实开发中,应根据应用场景选择符合的技能组合:
Web服务器
:TCP + 多线程/多进程
及时视频
:UDP + 多线程 + FEC
高并发服务
:线程池 + 非壅闭I/O
计算麋集型任务
:多进程充分使用多核
把握这些底层原理和实现技能,可以大概资助开发者构建高性能、高可靠的网络应用系统。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4