Socket是网络编程中用于实现不同主机或同一主机不同进程之间通信的编程接口,C++通过操作系统提供的Socket API可以完成基于TCP或UDP的网络通信开发。下面先介绍基础的TCP通信实现方式,TCP是面向连接的可靠传输协议,适合对数据完整性要求较高的场景。

TCP通信的服务端实现
TCP服务端的核心流程包括创建Socket、绑定端口、监听连接、接受客户端连接、收发数据、关闭连接几个步骤,以下是Windows平台下的实现代码,Linux平台仅需要替换头文件和部分函数即可。
#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib") // 链接Windows Socket库
int main() {
// 初始化Winsock环境
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cout << "WSAStartup失败" << std::endl;
return 1;
}
// 创建服务端Socket,AF_INET表示IPv4,SOCK_STREAM表示TCP协议
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
std::cout << "创建Socket失败,错误码:" << WSAGetLastError() << std::endl;
WSACleanup();
return 1;
}
// 绑定端口和地址
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY; // 监听所有网卡
serverAddr.sin_port = htons(8888); // 端口号,需要转换为网络字节序
if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cout << "绑定端口失败,错误码:" << WSAGetLastError() << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
// 开始监听,第二个参数是等待连接队列的最大长度
if (listen(serverSocket, 5) == SOCKET_ERROR) {
std::cout << "监听失败,错误码:" << WSAGetLastError() << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
std::cout << "服务端启动成功,监听端口8888" << std::endl;
// 接受客户端连接
sockaddr_in clientAddr;
int clientAddrLen = sizeof(clientAddr);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientAddrLen);
if (clientSocket == INVALID_SOCKET) {
std::cout << "接受客户端连接失败,错误码:" << WSAGetLastError() << std::endl;
closesocket(serverSocket);
WSACleanup();
return 1;
}
std::cout << "客户端连接成功" << std::endl;
// 接收客户端发送的数据
char recvBuf[1024] = {0};
int recvLen = recv(clientSocket, recvBuf, sizeof(recvBuf), 0);
if (recvLen > 0) {
std::cout << "收到客户端数据:" << recvBuf << std::endl;
// 向客户端发送响应数据
const char* sendBuf = "服务端已收到你的消息";
send(clientSocket, sendBuf, strlen(sendBuf), 0);
}
// 关闭Socket,清理Winsock环境
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
return 0;
}
TCP通信的客户端实现
TCP客户端的流程相对简单,主要包括创建Socket、连接服务端、收发数据、关闭连接几个步骤,以下是对应客户端代码:
#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
int main() {
// 初始化Winsock环境
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cout << "WSAStartup失败" << std::endl;
return 1;
}
// 创建客户端Socket
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET) {
std::cout << "创建Socket失败,错误码:" << WSAGetLastError() << std::endl;
WSACleanup();
return 1;
}
// 设置要连接的服务端地址和端口
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8888); // 服务端端口
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 连接本地服务端,也可以替换为其他服务端IP
// 连接服务端
if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cout << "连接服务端失败,错误码:" << WSAGetLastError() << std::endl;
closesocket(clientSocket);
WSACleanup();
return 1;
}
std::cout << "连接服务端成功" << std::endl;
// 向服务端发送数据
const char* sendBuf = "你好,我是客户端";
send(clientSocket, sendBuf, strlen(sendBuf), 0);
// 接收服务端响应数据
char recvBuf[1024] = {0};
int recvLen = recv(clientSocket, recvBuf, sizeof(recvBuf), 0);
if (recvLen > 0) {
std::cout << "收到服务端响应:" << recvBuf << std::endl;
}
// 关闭Socket,清理环境
closesocket(clientSocket);
WSACleanup();
return 0;
}
UDP通信的实现方式
UDP是无连接的不可靠传输协议,适合对实时性要求高、能容忍少量丢包的场景,比如视频流、实时游戏数据传输等。UDP不需要建立连接,直接通过sendto和recvfrom函数完成数据收发,以下是简单的UDP服务端示例:
#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
int main() {
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
SOCKET udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(9999);
bind(udpSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
std::cout << "UDP服务端启动,监听端口9999" << std::endl;
char recvBuf[1024] = {0};
sockaddr_in clientAddr;
int clientAddrLen = sizeof(clientAddr);
// 接收客户端数据,同时获取客户端地址
int recvLen = recvfrom(udpSocket, recvBuf, sizeof(recvBuf), 0, (sockaddr*)&clientAddr, &clientAddrLen);
if (recvLen > 0) {
std::cout << "收到UDP客户端数据:" << recvBuf << std::endl;
// 向客户端发送响应
const char* sendBuf = "UDP服务端已收到消息";
sendto(udpSocket, sendBuf, strlen(sendBuf), 0, (sockaddr*)&clientAddr, clientAddrLen);
}
closesocket(udpSocket);
WSACleanup();
return 0;
}
注意事项
- Windows平台使用Socket需要先调用
WSAStartup初始化环境,程序结束前调用WSACleanup清理,Linux平台不需要这两个步骤,直接包含<sys/socket.h>等头文件即可。 - 端口号需要使用
htons转换为网络字节序,IP地址需要使用inet_addr转换,避免字节序问题导致连接失败。 - 实际开发中需要添加更多的错误处理和异常捕获逻辑,比如连接断开后的重连机制、数据分包粘包的处理等。
- 如果需要在公网环境通信,需要注意防火墙端口开放,以及服务端绑定公网IP地址。