C++网络编程socket基础

Socket编程是实现网络通信的基础。C++程序使用系统socket API构建客户端-服务器应用,支持TCP和UDP协议。

TCP服务器使用bind、listen、accept流程。

#include
#include
#include
#include
#include

#ifdef _WIN32
#include
#include
#pragma comment(lib, "ws2_32.lib")
#else
#include
#include
#include
#include
#define SOCKET int
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define closesocket close
#endif

class TCPServer {
int server_fd_;
int port_;

bool init() {
#ifdef _WIN32
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return false;
#endif
server_fd_ = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd_ < 0) return false;

int opt = 1;
setsockopt(server_fd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
return true;
}

public:
TCPServer(int port) : server_fd_(-1), port_(port) {}

~TCPServer() {
if (server_fd_ >= 0) closesocket(server_fd_);
#ifdef _WIN32
WSACleanup();
#endif
}

bool start() {
if (!init()) return false;

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port_);

if (bind(server_fd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
std::cerr << "Bind failed\n";
return false;
}

if (listen(server_fd_, 5) < 0) {
std::cerr << "Listen failed\n";
return false;
}

std::cout << "Server on port " << port_ << "\n";
return true;
}

void accept_loop() {
struct sockaddr_in client;
socklen_t client_len = sizeof(client);

while (true) {
int client_fd = accept(server_fd_, (struct sockaddr*)&client, &client_len);
if (client_fd < 0) continue;

std::cout << "Client connected: "
<< inet_ntoa(client.sin_addr) << "\n";

std::thread([client_fd]() {
char buffer[1024] = {0};
const char* response = "Hello from C++ server\n";
send(client_fd, response, strlen(response), 0);

int bytes = recv(client_fd, buffer, sizeof(buffer) - 1, 0);
if (bytes > 0) {
buffer[bytes] = '\0';
std::cout << "Received: " << buffer << "\n";
}

closesocket(client_fd);
}).detach();
}
}
};

TCP客户端连接服务器。

class TCPClient {
int sock_;

public:
TCPClient() : sock_(-1) {
#ifdef _WIN32
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
#endif
}

~TCPClient() {
if (sock_ >= 0) closesocket(sock_);
#ifdef _WIN32
WSACleanup();
#endif
}

bool connect(const std::string& host, int port) {
sock_ = socket(AF_INET, SOCK_STREAM, 0);
if (sock_ < 0) return false;

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
inet_pton(AF_INET, host.c_str(), &addr.sin_addr);

if (::connect(sock_, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
return false;
}

return true;
}

std::string receive() {
char buffer[1024] = {0};
int bytes = recv(sock_, buffer, sizeof(buffer) - 1, 0);
if (bytes > 0) {
buffer[bytes] = '\0';
return std::string(buffer);
}
return "";
}

void send_data(const std::string& data) {
send(sock_, data.c_str(), data.length(), 0);
}
};

UDP服务器。

class UDPServer {
int sock_;
public:
UDPServer(int port) {
sock_ = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
bind(sock_, (struct sockaddr*)&addr, sizeof(addr));
std::cout << "UDP server on port " << port << "\n";
}

std::string receive() {
char buffer[1024];
struct sockaddr_in client;
socklen_t len = sizeof(client);
int n = recvfrom(sock_, buffer, sizeof(buffer) - 1, 0,
(struct sockaddr*)&client, &len);
if (n > 0) {
buffer[n] = '\0';
return std::string(buffer);
}
return "";
}

~UDPServer() { closesocket(sock_); }
};

非阻塞IO设置。

void set_nonblocking(int sock) {
#ifdef _WIN32
u_long mode = 1;
ioctlsocket(sock, FIONBIO, &mode);
#else
int flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
#endif
}

select多路复用。

void select_demo(int server_fd) {
fd_set readfds;
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;

FD_ZERO(&readfds);
FD_SET(server_fd, &readfds);

int activity = select(server_fd + 1, &readfds, nullptr, nullptr, &tv);
if (activity < 0) {
std::cerr << "Select error\n";
} else if (activity == 0) {
std::cout << "Timeout\n";
} else {
if (FD_ISSET(server_fd, &readfds)) {
std::cout << "New connection available\n";
}
}
}

HTTP服务器简单实现。

void http_response(int client_fd) {
const char* response =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"

Hello from C++

";

send(client_fd, response, strlen(response), 0);
}

网络编程是构建分布式系统和网络服务的基础。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐