C++网络编程之Socket
1.介绍
在C++网络编程中,Socket是实现网络通信的核心工具,C++本身并没有直接提供socket接口,而是通过操作系统提供的Berkeley Socket API 来实现网络通信。下面将详细介绍一下如何用C++进行socket编程。
2.socket的基本概念
socket是网络通信的端点,包含IP地址和端口号,用于标识通信的双方。通过socket,应用程序可以发送和接收数据。
socket的类型主要有三种:
1.流式socket(sock_stream):基于TCP,提供可靠的、面向连接的通信,确保数据顺序和完整性。
2.数据报socket(sock_dgram):基于UDP,提供无连接的通信,速度快但不保证可靠性。
3.原始socket(sock_raw):允许直接访问底层协议(IP、ICMP),通常用于开发自定义协议。
3.socket的基本工作流程
(1)服务器端
1.创建socket:使用socket()函数创建一个socket。
2.绑定地址:使用bind()将socket绑定到指定的IP地址和端口。
3.监听连接:使用listen()开始监听客户端连接。
4.结构连接:使用accept()接收客户端的连接请求。
5.数据交换:使用recv()和send()进行数据收发。
6.关闭socket:使用close()关闭连接。
(2)客户端
1.创建socket:使用socket()函数创建一个socket。
2.连接服务器:使用connect()连接到服务器。
3.数据交换:使用recv()和send()进行数据收发。
4.关闭socket:使用close()关闭连接。
4.C++socket编程示例
(1)服务器端代码
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
// 创建 Socket
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
std::cerr << "无法创建 Socket\n";
return 1;
}
// 绑定地址
sockaddr_in server_addr{};
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有网络接口
server_addr.sin_port = htons(12345); // 监听端口 12345
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) {
std::cerr << "绑定失败\n";
close(server_socket);
return 1;
}
// 监听连接
if (listen(server_socket, 5) == -1) {
std::cerr << "监听失败\n";
close(server_socket);
return 1;
}
std::cout << "服务器正在监听端口 12345...\n";
// 接受连接
sockaddr_in client_addr{};
socklen_t client_addr_len = sizeof(client_addr);
int client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_len);
if (client_socket == -1) {
std::cerr << "接受连接失败\n";
close(server_socket);
return 1;
}
std::cout << "客户端已连接\n";
// 接收数据
char buffer[1024];
int bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
if (bytes_received == -1) {
std::cerr << "接收数据失败\n";
} else {
buffer[bytes_received] = '\0';
std::cout << "收到数据: " << buffer << std::endl;
}
// 发送数据
const char* response = "你好,客户端!";
send(client_socket, response, strlen(response), 0);
// 关闭 Socket
close(client_socket);
close(server_socket);
return 0;
}
(2)客户端代码
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
// 创建 Socket
int client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket == -1) {
std::cerr << "无法创建 Socket\n";
return 1;
}
// 连接服务器
sockaddr_in server_addr{};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(12345); // 服务器端口
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); // 服务器 IP 地址
if (connect(client_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) {
std::cerr << "连接服务器失败\n";
close(client_socket);
return 1;
}
std::cout << "已连接到服务器\n";
// 发送数据
const char* message = "你好,服务器!";
send(client_socket, message, strlen(message), 0);
// 接收数据
char buffer[1024];
int bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
if (bytes_received == -1) {
std::cerr << "接收数据失败\n";
} else {
buffer[bytes_received] = '\0';
std::cout << "收到数据: " << buffer << std::endl;
}
// 关闭 Socket
close(client_socket);
return 0;
}
5.一些关键问题
(1)地址结构
sockaddr_in是IPv4的地址结构,包含IP地址和端口号。
inet_pton()是将字符串形式的IP地址转换为二进制形式。
(2)字节序转换
htons()和htonl()用于将主机字节序转换为网络字节序。
ntos()和ntohl()用于将网络字节序转换为主机字节序。
(3)错误处理
每个函数掉用户都应该检查返回值,确保操作成功。
(4)多客户端支持
服务器端可以使用多线程或多进程处理多个客户端连接。
6.其他常见问题
(1)socket阻塞和非阻塞
默认情况下socket是阻塞的,可以使用fcntl()或ioctl()设置为非阻塞模式。
(2)地址重用
使用setsockopt()设置SO_REUSEADDR选项,允许地址重用。
(3)超时设置
使用setsockopt()设置SO_RCVTIMEO和SO_SNDTIMEO选项,设置接收和发送的超时时间。
7.总结
Socket 是网络编程的核心工具,掌握其基本概念和工作流程对于开发网络应用至关重要。
如有错误,敬请指正!!!