在Linux环境下使用C++进行网络编程时,处理并发连接是一个常见的需求。以下是几种常用的方法来处理并发连接:
多线程是最直观的并发处理方式。每个连接由一个单独的线程处理。
#include <iostream>
#include <thread>
#include <vector>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
void handleClient(int clientSocket) {
char buffer[1024];
while (true) {
int bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesReceived <= 0) {
break;
}
send(clientSocket, buffer, bytesReceived, 0);
}
close(clientSocket);
}
int main() {
int serverSocket, clientSocket;
struct sockaddr_in serverAddr, clientAddr;
socklen_t clientAddrLen = sizeof(clientAddr);
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket < 0) {
perror("socket");
return 1;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080);
if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
perror("bind");
return 1;
}
if (listen(serverSocket, 5) < 0) {
perror("listen");
return 1;
}
while (true) {
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrLen);
if (clientSocket < 0) {
perror("accept");
continue;
}
std::thread(handleClient, clientSocket).detach();
}
close(serverSocket);
return 0;
}
多进程模型中,每个连接由一个单独的进程处理。
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/wait.h>
void handleClient(int clientSocket) {
char buffer[1024];
while (true) {
int bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesReceived <= 0) {
break;
}
send(clientSocket, buffer, bytesReceived, 0);
}
close(clientSocket);
}
int main() {
int serverSocket, clientSocket;
struct sockaddr_in serverAddr, clientAddr;
socklen_t clientAddrLen = sizeof(clientAddr);
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket < 0) {
perror("socket");
return 1;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080);
if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
perror("bind");
return 1;
}
if (listen(serverSocket, 5) < 0) {
perror("listen");
return 1;
}
while (true) {
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrLen);
if (clientSocket < 0) {
perror("accept");
continue;
}
pid_t pid = fork();
if (pid == 0) {
close(serverSocket);
handleClient(clientSocket);
exit(0);
} else if (pid > 0) {
close(clientSocket);
} else {
perror("fork");
}
}
close(serverSocket);
return 0;
}
I/O多路复用模型允许单个进程/线程处理多个连接。常用的系统调用有select
、poll
和epoll
。
select
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/select.h>
int main() {
int serverSocket, clientSocket;
struct sockaddr_in serverAddr;
fd_set readfds;
int maxClients = 10;
int clientSockets[maxClients] = {0};
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket < 0) {
perror("socket");
return 1;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080);
if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
perror("bind");
return 1;
}
if (listen(serverSocket, 5) < 0) {
perror("listen");
return 1;
}
while (true) {
FD_ZERO(&readfds);
FD_SET(serverSocket, &readfds);
int maxFd = serverSocket;
for (int i = 0; i < maxClients; i++) {
clientSocket = clientSockets[i];
if (clientSocket > 0) {
FD_SET(clientSocket, &readfds);
}
if (clientSocket > maxFd) {
maxFd = clientSocket;
}
}
int activity = select(maxFd + 1, &readfds, NULL, NULL, NULL);
if (activity < 0) {
perror("select");
continue;
}
if (FD_ISSET(serverSocket, &readfds)) {
clientSocket = accept(serverSocket, NULL, NULL);
if (clientSocket < 0) {
perror("accept");
continue;
}
for (int i = 0; i < maxClients; i++) {
if (clientSockets[i] == 0) {
clientSockets[i] = clientSocket;
break;
}
}
}
for (int i = 0; i < maxClients; i++) {
clientSocket = clientSockets[i];
if (FD_ISSET(clientSocket, &readfds)) {
char buffer[1024];
int bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesReceived <= 0) {
close(clientSocket);
clientSockets[i] = 0;
} else {
send(clientSocket, buffer, bytesReceived, 0);
}
}
}
}
close(serverSocket);
return 0;
}
epoll
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/epoll.h>
int main() {
int serverSocket, clientSocket, epollFd;
struct sockaddr_in serverAddr;
struct epoll_event event, events[10];
int maxEvents = 10;
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket < 0) {
perror("socket");
return 1;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(8080);
if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
perror("bind");
return 1;
}
if (listen(serverSocket, 5) < 0) {
perror("listen");
return 1;
}
epollFd = epoll_create1(0);
if (epollFd < 0) {
perror("epoll_create1");
return 1;
}
event.events = EPOLLIN;
event.data.fd = serverSocket;
if (epoll_ctl(epollFd, EPOLL_CTL_ADD, serverSocket, &event) < 0) {
perror("epoll_ctl: serverSocket");
return 1;
}
while (true) {
int numEvents = epoll_wait(epollFd, events, maxEvents, -1);
if (numEvents < 0) {
perror("epoll_wait");
continue;
}
for (int i = 0; i < numEvents; i++) {
if (events[i].data.fd == serverSocket) {
clientSocket = accept(serverSocket, NULL, NULL);
if (clientSocket < 0) {
perror("accept");
continue;
}
event.events = EPOLLIN | EPOLLET;
event.data.fd = clientSocket;
if (epoll_ctl(epollFd, EPOLL_CTL_ADD, clientSocket, &event) < 0) {
perror("epoll_ctl: clientSocket");
close(clientSocket);
}
} else {
clientSocket = events[i].data.fd;
char buffer[1024];
int bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesReceived <= 0) {
close(clientSocket);
epoll_ctl(epollFd, EPOLL_CTL_DEL, clientSocket, NULL);
} else {
send(clientSocket, buffer, bytesReceived, 0);
}
}
}
}
close(serverSocket);
close(epollFd);
return 0;
}
选择哪种方法取决于具体应用场景和性能需求。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
推荐阅读:C++ Linux网络编程难点在哪