- C++基础
- C++主页
- C++概述
- C++环境设置
- C++基本语法
- C++注释
- C++ Hello World
- C++省略命名空间
- C++常量/字面量
- C++关键字
- C++标识符
- C++数据类型
- C++数值数据类型
- C++字符数据类型
- C++布尔数据类型
- C++变量类型
- C++变量作用域
- C++多个变量
- C++基本输入/输出
- C++修饰符类型
- C++存储类
- C++运算符
- C++数字
- C++枚举
- C++引用
- C++日期和时间
- C++控制语句
- C++决策
- C++ if 语句
- C++ if else 语句
- C++嵌套 if 语句
- C++ switch 语句
- C++嵌套 switch 语句
- C++循环类型
- C++ while 循环
- C++ for 循环
- C++ do while 循环
- C++ foreach 循环
- C++嵌套循环
- C++ break 语句
- C++ continue 语句
- C++ goto 语句
- C++构造函数
- C++构造函数和析构函数
- C++复制构造函数
C++套接字编程
C++套接字编程是使用C++在网络上建立两个套接字之间通信的方法。在本教程中,我们将学习使用C++中不同类型的套接字进行套接字编程的全部内容。
什么是套接字?
套接字充当网络数据交换的接触点,就像在网络上发送和接收数据的端点一样。它们允许应用程序使用TCP(传输控制协议)和UDP(用户数据报协议)等协议相互通信。它们是大多数互联网通信的基础,因为它使我们能够从网络浏览到实时聊天。
套接字有两种类型
- 流式套接字(TCP):它提供可靠的、面向连接的通信,其中数据以连续流的形式发送,确保数据包按顺序到达且没有错误。
- 数据报套接字(UDP):它提供无连接的通信。它独立地以数据包的形式传输数据,但不保证顺序或交付,使其以快速但不可靠的方式发送。
C++中的套接字编程
C++中的套接字编程是一种强大的方法,用于创建网络应用程序,这些应用程序允许使用套接字API通过网络在设备之间进行通信。此过程涉及在客户端和服务器之间建立连接,从而能够通过TCP或UDP等协议进行数据交换。
C++服务器端套接字(侦听连接)
以下方法用于处理服务器端通信
1. socket()
socket()是网络编程中的系统调用,它在C++中创建一个新的TCP套接字,该套接字定义在<sys/socket.h>头文件中。
语法
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
其中,
- int sockfd声明一个整数变量,该变量将存储套接字文件描述符。
- AF_INET表示套接字将使用IPv4地址族。
- SOCK_STREAM指定套接字将使用TCP(面向流的协议),并且
- 0允许系统为指定的地址族和套接字类型(在这种情况下为TCP)选择默认协议。
2. bind()
bind()方法与套接字关联,具有特定的本地地址和端口号,允许套接字侦听该地址上的传入连接。
语法
bind(sockfd, (struct sockaddr*)&address, sizeof(address));
其中,
- sockfd是表示程序中套接字的文件描述符,用于执行各种套接字操作
- (struct sockaddr)&address将地址结构转换为bind函数的通用指针类型。
- sizeof(address)指定地址结构的大小,以告知系统预期多少数据。
3. listen()
listen()函数将套接字标记为被动套接字,这准备了一个套接字以接受传入的连接请求(对于服务器)。
语法
listen(sockfd, 10);
其中,
- sockfd是表示程序中套接字的文件描述符,用于执行各种套接字操作
- 10是积压参数,它指定服务器繁忙时可以排队的最大待处理连接数。
4. accept()
accept()函数接受来自客户端的新连接(对于服务器)。它从待处理连接队列中提取第一个连接请求,并为该连接创建一个新的套接字。
语法
int clientSocket = accept(sockfd, (struct sockaddr*)&clientAddress, &clientLen);
其中,
- sockfd:它是套接字的文件描述符,用于执行各种套接字操作。
- (struct sockaddr)&address:这是一个类型转换,它将clientAddress的指针类型转换为struct sockaddr*类型的指针。
- &clientLen:它是指向一个变量的指针,该变量保存clientAddress的大小。
C++客户端套接字(连接到服务器)
以下方法用于客户端通信
1. connect()
此函数是一个系统调用,它尝试使用套接字建立与指定服务器的连接(对于客户端)。
语法
connect(sockfd, (struct sockaddr*)&serverAddress, sizeof(serverAddress));
其中,
- sockfd是表示程序中套接字的文件描述符,用于执行各种套接字操作。
- (struct sockaddr*)&serverAddress将serverAddress转换为struct sockaddr*指针,这使得它与需要通用套接字地址类型的函数兼容。
- sizeof(serverAddress)指定serverAddress的大小
2. send()
send()函数是套接字编程中的系统调用,它将数据发送到已连接的套接字。
语法
send(sockfd, "Hello", strlen("Hello"), 0);
其中,
- sockfd是表示程序中套接字的文件描述符,用于执行各种套接字操作。
- strlen("Hello")函数返回字符串“Hello”(5个字节)的长度,显示要发送多少字节的数据。
- 0允许系统为指定的地址族和套接字类型(在这种情况下为TCP)选择默认协议。
3. recv()
recv()函数是一个系统调用,用于从已连接的套接字接收数据,允许客户端或服务器读取传入的消息。
语法
recv(sockfd, buffer, sizeof(buffer), 0);
其中,
- sockfd是表示程序中套接字的文件描述符,用于执行各种套接字操作。
- buffer是指向内存位置的指针,接收到的数据将存储在此处。此缓冲区应足够大以容纳传入的数据。
- sizeof(buffer)指定要从套接字读取的最大字节数,这通常是缓冲区的大小。
关闭客户端套接字
close()方法关闭打开的套接字。
语法
close(sockfd);
其中,
- close函数是一个系统调用,它关闭与套接字关联的文件描述符。
套接字编程所需的标头文件
在C或C++中使用套接字进行编程时,必须包含特定标头文件才能进行必要的声明。
对于Linux/Unix系统
- <sys/socket.h>
- <netinet/in.h>
- <arpa/inet.h>
- <unistd.h>
- <string.h>
- <errno.h>
对于Windows系统
- <winsock2.h>
- <ws2tcpip.h>
- <windows.h>
C++套接字编程示例
这是一个简单的示例,用于说明C++中的TCP服务器和客户端
TCP服务器代码
#include <netinet/in.h> #include <sys/socket.h> #include <unistd.h> #include <cstring> #include <iostream> #define PORT 8080 int main() { int server_fd, new_socket; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); char buffer[1024] = {0}; // Create socket server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // Attach socket to the port setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); // Bind if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // Listen if (listen(server_fd, 3) < 0) { perror("listen"); exit(EXIT_FAILURE); } // Accept a connection new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen); if (new_socket < 0) { perror("accept"); exit(EXIT_FAILURE); } // Read data read(new_socket, buffer, 1024); std::cout << "Message from client: " << buffer << std::endl; // Close socket close(new_socket); close(server_fd); return 0; }
TCP客户端代码
#include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <unistd.h> #include <cstring> #include <iostream> #define PORT 8080 int main() { int sock = 0; struct sockaddr_in serv_addr; const char *hello = "Hello from client"; // Create socket sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { std::cerr << "Socket creation error" << std::endl; return -1; } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); // Convert IPv4 and IPv6 addresses from text to binary if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { std::cerr << "Invalid address/ Address not supported" << std::endl; return -1; } // Connect to server if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { std::cerr << "Connection Failed" << std::endl; return -1; } // Send data send(sock, hello, strlen(hello), 0); std::cout << "Message sent" << std::endl; // Close socket close(sock); return 0; }
编译和运行步骤
以下是编译和运行客户端套接字程序的步骤
编译服务器和客户端代码文件
g++ -o server server.cpp g++ -o client client.cpp
运行服务器
./server
运行客户端(在另一个终端中)
./client
最佳实践
- 错误处理:始终检查套接字函数的返回值以正确处理错误。
- 阻塞与非阻塞:默认情况下,套接字以阻塞模式运行。因此,请考虑使用非阻塞套接字或多路复用(如select或poll)来处理多个连接。
- 跨平台问题:此示例适用于Unix/Linux。对于Windows,您需要包含<winsock2.h>并使用WSAStartup()初始化Winsock。
实际应用
套接字在现实生活中的应用和工具等方面有各种应用,这里列举了一些。
这些示例演示了如何将套接字用于不同的应用程序
- 回显服务器:一个简单的服务器,它会回显收到的消息。
- 聊天应用程序:一个多线程服务器,允许多个客户端聊天。
- FTP客户端/服务器:通过网络传输文件的简单实现。
- Web服务器:套接字处理HTTP请求和响应以提供Web内容。
- 在线多人游戏:套接字支持玩家和游戏服务器之间的实时通信。
- 远程访问工具:套接字提供用于远程管理服务器的安全连接。
- VoIP应用程序:套接字实时传输音频和视频数据以进行通信。
- 流媒体服务:套接字将连续的音频和视频内容传递给用户。
- 物联网设备:套接字促进智能设备和服务器之间的通信。
- 实时协作工具:套接字允许用户之间即时共享编辑和消息。
- 数据同步服务:套接字管理设备和服务器之间的文件上传和下载。
- 天气监测系统:套接字将实时天气数据发送到中央服务器进行分析。
- 支付处理系统:套接字安全地传输客户端和银行之间的交易数据。
- 聊天机器人:套接字能够在对话界面中实现即时消息传递和响应。