Socket详解及C++应用示例

Socket详解及C++应用示例

一、Socket基本概念1.1 定义Socket(套接字)是计算机网络中进程间通信的一种机制,它提供了不同主机或同一主机上不同进程之间进行数据交换的端点。Socket本质上是一个编程接口(API),封装了TCP/IP协议栈的复杂实现,使开发者能便捷地实现网络通信。

1.2 核心作用实现跨进程/跨主机的数据传输提供可靠的字节流传输(TCP)或无连接的数据报传输(UDP)支持多种网络协议(TCP、UDP、ICMP等)允许应用程序通过端口号区分不同服务1.3 主要类型类型

协议

特点

应用场景

SOCK_STREAM

TCP

面向连接、可靠传输、字节流、双工通信

HTTP/HTTPS、文件传输、邮件

SOCK_DGRAM

UDP

无连接、不可靠、数据报、效率高

视频流、语音通话、DNS查询

SOCK_RAW

原始协议

直接访问IP层,用于协议开发

网络诊断工具、自定义协议

1.4 通信模型Socket通信基于客户端-服务器(C/S)模型:

服务器:创建Socket → 绑定端口 → 监听连接 → 接受请求 → 数据交互客户端:创建Socket → 连接服务器 → 数据交互二、TCP Socket编程示例(C++)2.1 TCP服务器端实现代码语言:cpp复制#include

#include

#include

#include

#include

#include

const int PORT = 8080;

const int BUFFER_SIZE = 1024;

int main() {

// 1. 创建TCP套接字

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

if (server_fd == -1) {

std::cerr << "Socket creation failed: " << strerror(errno) << std::endl;

return -1;

}

// 2. 设置地址重用,避免端口占用问题

int opt = 1;

if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {

std::cerr << "Setsockopt failed: " << strerror(errno) << std::endl;

close(server_fd);

return -1;

}

// 3. 绑定地址和端口

sockaddr_in address;

int addrlen = sizeof(address);

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) {

std::cerr << "Bind failed: " << strerror(errno) << std::endl;

close(server_fd);

return -1;

}

// 4. 监听连接请求(最大等待队列长度为3)

if (listen(server_fd, 3) < 0) {

std::cerr << "Listen failed: " << strerror(errno) << std::endl;

close(server_fd);

return -1;

}

std::cout << "Server listening on port " << PORT << std::endl;

// 5. 接受客户端连接

int new_socket;

sockaddr_in client_addr;

int client_addr_len = sizeof(client_addr);

if ((new_socket = accept(server_fd, (struct sockaddr *)&client_addr,

(socklen_t*)&client_addr_len)) < 0) {

std::cerr << "Accept failed: " << strerror(errno) << std::endl;

close(server_fd);

return -1;

}

char client_ip[INET_ADDRSTRLEN];

inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);

std::cout << "Accepted connection from " << client_ip << ":"

<< ntohs(client_addr.sin_port) << std::endl;

// 6. 数据交互

char buffer[BUFFER_SIZE] = {0};

ssize_t valread = read(new_socket, buffer, BUFFER_SIZE);

std::cout << "Received: " << buffer << std::endl;

const char *response = "Hello from TCP server";

send(new_socket, response, strlen(response), 0);

std::cout << "Response sent" << std::endl;

// 7. 关闭连接

close(new_socket);

close(server_fd);

return 0;

}2.2 TCP客户端实现代码语言:cpp复制#include

#include

#include

#include

#include

#include

const char* SERVER_IP = "127.0.0.1";

const int PORT = 8080;

const int BUFFER_SIZE = 1024;

int main() {

// 1. 创建TCP套接字

int sock = socket(AF_INET, SOCK_STREAM, 0);

if (sock == -1) {

std::cerr << "Socket creation failed: " << strerror(errno) << std::endl;

return -1;

}

// 2. 设置服务器地址

sockaddr_in serv_addr;

serv_addr.sin_family = AF_INET;

serv_addr.sin_port = htons(PORT);

// 转换IP地址为二进制格式

if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {

std::cerr << "Invalid address or address not supported" << std::endl;

close(sock);

return -1;

}

// 3. 连接服务器

if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {

std::cerr << "Connection failed: " << strerror(errno) << std::endl;

close(sock);

return -1;

}

std::cout << "Connected to server " << SERVER_IP << ":" << PORT << std::endl;

// 4. 发送数据

const char *message = "Hello from TCP client";

send(sock, message, strlen(message), 0);

std::cout << "Message sent" << std::endl;

// 5. 接收响应

char buffer[BUFFER_SIZE] = {0};

ssize_t valread = read(sock, buffer, BUFFER_SIZE);

std::cout << "Received: " << buffer << std::endl;

// 6. 关闭连接

close(sock);

return 0;

}三、UDP Socket编程示例(C++)3.1 UDP服务器端实现代码语言:cpp复制#include

#include

#include

#include

#include

#include

const int PORT = 8080;

const int BUFFER_SIZE = 1024;

int main() {

// 1. 创建UDP套接字

int server_fd = socket(AF_INET, SOCK_DGRAM, 0);

if (server_fd == -1) {

std::cerr << "Socket creation failed: " << strerror(errno) << std::endl;

return -1;

}

// 2. 设置地址重用

int opt = 1;

if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {

std::cerr << "Setsockopt failed: " << strerror(errno) << std::endl;

close(server_fd);

return -1;

}

// 3. 绑定地址和端口

sockaddr_in address;

int addrlen = sizeof(address);

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) {

std::cerr << "Bind failed: " << strerror(errno) << std::endl;

close(server_fd);

return -1;

}

std::cout << "UDP Server listening on port " << PORT << std::endl;

// 4. 接收和发送数据

char buffer[BUFFER_SIZE] = {0};

sockaddr_in client_addr;

int client_addr_len = sizeof(client_addr);

while (true) {

// 接收客户端消息

ssize_t len = recvfrom(server_fd, buffer, BUFFER_SIZE, 0,

(struct sockaddr *)&client_addr, (socklen_t*)&client_addr_len);

if (len < 0) {

std::cerr << "Recvfrom failed: " << strerror(errno) << std::endl;

continue;

}

buffer[len] = '\0'; // 添加字符串结束符

char client_ip[INET_ADDRSTRLEN];

inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);

std::cout << "Received from " << client_ip << ":" << ntohs(client_addr.sin_port)

<< ": " << buffer << std::endl;

// 发送响应

const char *response = "Hello from UDP server";

sendto(server_fd, response, strlen(response), 0,

(struct sockaddr *)&client_addr, client_addr_len);

}

// 注意:UDP服务器通常不会主动关闭,此处为示例完整性添加

close(server_fd);

return 0;

}3.2 UDP客户端实现代码语言:cpp复制#include

#include

#include

#include

#include

#include

const char* SERVER_IP = "127.0.0.1";

const int PORT = 8080;

const int BUFFER_SIZE = 1024;

int main() {

// 1. 创建UDP套接字

int sock = socket(AF_INET, SOCK_DGRAM, 0);

if (sock == -1) {

std::cerr << "Socket creation failed: " << strerror(errno) << std::endl;

return -1;

}

// 2. 设置服务器地址

sockaddr_in serv_addr;

serv_addr.sin_family = AF_INET;

serv_addr.sin_port = htons(PORT);

if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {

std::cerr << "Invalid address or address not supported" << std::endl;

close(sock);

return -1;

}

// 3. 发送数据

const char *message = "Hello from UDP client";

sendto(sock, message, strlen(message), 0,

(struct sockaddr *)&serv_addr, sizeof(serv_addr));

std::cout << "Message sent to " << SERVER_IP << ":" << PORT << std::endl;

// 4. 接收响应

char buffer[BUFFER_SIZE] = {0};

sockaddr_in server_response_addr;

int server_addr_len = sizeof(server_response_addr);

ssize_t len = recvfrom(sock, buffer, BUFFER_SIZE, 0,

(struct sockaddr *)&server_response_addr, (socklen_t*)&server_addr_len);

if (len < 0) {

std::cerr << "Recvfrom failed: " << strerror(errno) << std::endl;

close(sock);

return -1;

}

buffer[len] = '\0';

std::cout << "Received: " << buffer << std::endl;

// 5. 关闭套接字

close(sock);

return 0;

}四、跨平台注意事项4.1 Windows与Linux的主要差异特性

Windows (Winsock)

Linux/Unix

头文件

#include

#include

初始化

需要WSAStartup()

无需初始化

错误处理

WSAGetLastError()

errno全局变量

关闭套接字

closesocket()

close()

库链接

需要链接ws2_32.lib

无需额外库

4.2 跨平台示例代码(TCP服务器)代码语言:cpp复制#include

#include

#ifdef _WIN32

#include

#pragma comment(lib, "ws2_32.lib")

#else

#include

#include

#include

#include

#include

#endif

const int PORT = 8080;

const int BUFFER_SIZE = 1024;

int main() {

#ifdef _WIN32

// Windows初始化Winsock

WSADATA wsaData;

if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {

std::cerr << "WSAStartup failed: " << WSAGetLastError() << std::endl;

return -1;

}

#endif

// 创建套接字代码(与前面相同)

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

if (server_fd == -1) {

std::cerr << "Socket creation failed: "

#ifdef _WIN32

<< WSAGetLastError()

#else

<< strerror(errno)

#endif

<< std::endl;

#ifdef _WIN32

WSACleanup();

#endif

return -1;

}

// ... 其余代码(绑定、监听、接受连接等)...

// 关闭资源

#ifdef _WIN32

closesocket(server_fd);

WSACleanup();

#else

close(server_fd);

#endif

return 0;

}五、现代C++网络编程选项5.1 C++标准网络库(C++20 Networking TS)C++20引入了标准网络库,提供了现代、类型安全的网络编程接口:

代码语言:cpp复制#include

#include

#include

using asio::ip::tcp;

int main() {

try {

asio::io_context io_context;

tcp::resolver resolver(io_context);

auto endpoints = resolver.resolve("example.com", "daytime");

tcp::socket socket(io_context);

asio::connect(socket, endpoints);

std::string data;

asio::error_code error;

asio::read(socket, asio::dynamic_buffer(data), error);

if (error == asio::error::eof) {

std::cout << "Received: " << data << std::endl;

} else if (error) {

throw std::system_error(error);

}

} catch (std::exception& e) {

std::cerr << "Exception: " << e.what() << std::endl;

}

return 0;

}5.2 Boost.Asio库Boost.Asio是广泛使用的跨平台网络库,也是C++标准网络库的基础:

代码语言:cpp复制#include

#include

using boost::asio::ip::tcp;

int main() {

try {

boost::asio::io_context io_context;

tcp::socket socket(io_context);

tcp::resolver resolver(io_context);

boost::asio::connect(socket, resolver.resolve("localhost", "8080"));

std::string request = "Hello from Boost.Asio client";

boost::asio::write(socket, boost::asio::buffer(request));

char reply[1024];

size_t len = socket.read_some(boost::asio::buffer(reply));

std::cout << "Received: " << std::string(reply, len) << std::endl;

} catch (std::exception& e) {

std::cerr << "Exception: " << e.what() << std::endl;

}

return 0;

}六、Socket应用场景与常见问题6.1 典型应用场景客户端-服务器通信:Web浏览器与服务器、移动应用后端交互实时数据传输:在线游戏、视频会议、实时监控分布式系统:微服务间通信、进程间通信(IPC)物联网设备:传感器数据上报、设备控制指令6.2 常见问题及解决方案问题

解决方案

端口占用

使用SO_REUSEADDR选项;选择未被占用的高端口(1024-65535)

连接超时

设置SO_RCVTIMEO和SO_SNDTIMEO选项;实现应用层心跳机制

数据粘包

定义消息边界(长度前缀、分隔符);使用固定大小缓冲区

网络异常

实现重连机制;添加错误处理和日志记录

性能瓶颈

使用非阻塞I/O;实现I/O多路复用(select/poll/epoll);线程池处理连接

6.3 安全考虑使用TLS/SSL加密传输(如HTTPS)验证客户端身份(IP过滤、令牌认证)限制连接频率,防止DoS攻击输入验证,防止缓冲区溢出七、总结Socket是网络编程的基础,提供了进程间通信的通用接口。本文介绍了Socket的基本概念、TCP/UDP协议的C++实现示例、跨平台注意事项以及现代C++网络编程选项。通过掌握Socket编程,开发者可以构建各种网络应用,从简单的客户端-服务器程序到复杂的分布式系统。

实际开发中,除了基础的BSD Socket API,还可以考虑使用更高级的库如Boost.Asio或C++20标准网络库,以提高开发效率和代码质量。同时,需要注意网络编程中的错误处理、性能优化和安全问题,确保应用的可靠性和稳定性。

相关文章

字典葡萄牙文 - 中文
365bet娱乐在线

字典葡萄牙文 - 中文

⌛ 10-16 👁️ 9354
人力资源招聘广告怎么写?
365速发国际app

人力资源招聘广告怎么写?

⌛ 11-13 👁️ 9987