常用的并发处理方式
- 多进程方式:通过
fork
系统调用创建子进程来处理每个客户端连接。每个子进程有独立的地址空间,相互隔离,但进程间通信相对复杂,并且创建和销毁进程的开销较大。
- 多线程方式:使用
pthread
库创建线程来处理客户端连接。线程共享进程的地址空间,通信方便,创建和销毁开销相对较小,但需要注意线程同步问题,避免数据竞争。
- I/O多路复用方式:使用
select
、poll
或epoll
等I/O多路复用技术,在一个进程内处理多个客户端连接。这种方式不需要创建额外的进程或线程,资源开销小,但代码逻辑相对复杂,需要处理好事件的监听和分发。
多线程处理并发连接示例代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#define PORT 8080
#define BACKLOG 10
#define BUFFER_SIZE 1024
// 线程处理函数参数结构体
typedef struct {
int client_fd;
} ThreadArgs;
// 线程处理函数,处理客户端连接
void* handle_client(void* arg) {
ThreadArgs* args = (ThreadArgs*)arg;
int client_fd = args->client_fd;
char buffer[BUFFER_SIZE] = {0};
int valread = read(client_fd, buffer, BUFFER_SIZE);
if (valread < 0) {
perror("read failed");
} else if (valread > 0) {
buffer[valread] = '\0';
printf("Received: %s\n", buffer);
const char* response = "Hello from server!";
send(client_fd, response, strlen(response), 0);
}
close(client_fd);
free(args);
pthread_exit(NULL);
}
int main(int argc, char const *argv[]) {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
pthread_t tid;
// 创建套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置套接字选项
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);
// 绑定端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(server_fd, BACKLOG) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("Server is listening on port %d...\n", PORT);
while (1) {
// 接受客户端连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
continue;
}
// 为每个连接创建线程处理
ThreadArgs* args = (ThreadArgs*)malloc(sizeof(ThreadArgs));
args->client_fd = new_socket;
if (pthread_create(&tid, NULL, handle_client, (void*)args) != 0) {
perror("pthread_create");
free(args);
close(new_socket);
}
pthread_detach(tid);
}
close(server_fd);
return 0;
}