1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
| #include <sys/socket.h> #include <sys/types.h> #include <netdb.h> #include <cstring> #include <unistd.h> #include <cerrno> #include <cstdlib>
using namespace std;
/** * 建立TCP连接 * @param node 服务器域名或IP地址 * @param service 服务名或端口号 * @return 成功返回socket文件描述符,失败返回-1 */ int tcpConnect(const char* node, const char* service) { // 地址信息提示结构,用于指定getaddrinfo的查询条件 struct addrinfo hints; // 存储查询结果的指针 struct addrinfo *result, *p; // 初始化hints结构为0 memset(&hints, 0, sizeof(hints)); // 不指定地址族,支持IPv4和IPv6 hints.ai_family = AF_UNSPEC; // 指定套接字类型为TCP hints.ai_socktype = SOCK_STREAM;
// 解析域名和服务,获取地址信息 int err = getaddrinfo(node, service, &hints, &result); if (err != 0) { cerr << "解析地址失败: " << gai_strerror(err) << endl; return -1; }
int sockfd = -1; // 遍历所有可能的地址,尝试创建连接 for (p = result; p != nullptr; p = p->ai_next) { // 创建套接字 if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { cerr << "创建套接字失败: " << strerror(errno) << ", 尝试下一个地址..." << endl; continue; }
// 尝试连接到服务器 if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); // 连接失败,关闭当前套接字 cerr << "连接失败: " << strerror(errno) << ", 尝试下一个地址..." << endl; continue; }
// 连接成功,退出循环 break; }
// 释放地址信息结构占用的内存 freeaddrinfo(result);
// 检查是否成功建立连接 if (p == nullptr) { cerr << "所有地址尝试均失败,无法建立连接" << endl; return -1; }
return sockfd; }
/** * 发送数据,确保所有数据都被发送 * @param sockfd 套接字文件描述符 * @param data 要发送的数据 * @param len 数据长度 * @return 成功返回true,失败返回false */ bool sendAll(int sockfd, const char* data, size_t len) { size_t totalSent = 0; // 已发送的字节数 while (totalSent < len) { ssize_t sent = send(sockfd, data + totalSent, len - totalSent, 0); if (sent == -1) { cerr << "发送数据失败: " << strerror(errno) << endl; return false; } totalSent += sent; } return true; }
int main(int argc, char * argv[]) { // 目标服务器和服务 const char *node = "www.baidu.com"; const char *service = "http"; // HTTP默认端口80
// 建立TCP连接 int connfd = tcpConnect(node, service); if (connfd == -1) { cerr << "无法连接到 " << node << ":" << service << endl; return 1; } cout << "成功连接到 " << node << ":" << service << endl;
// 构造HTTP GET请求 // 注意:相邻的字符串字面值会在编译时自动拼接 const char* request = "GET / HTTP/1.1\r\n" "Host: www.baidu.com\r\n" "User-Agent: Simple TCP Client\r\n" "Connection: close\r\n\r\n"; // 发送HTTP请求 size_t requestLen = strlen(request); cout << "发送HTTP请求,长度: " << requestLen << " 字节" << endl; if (!sendAll(connfd, request, requestLen)) { cerr << "发送HTTP请求失败" << endl; close(connfd); return 1; }
// 接收并打印服务器响应 const size_t BUFFER_SIZE = 4096; char buffer[BUFFER_SIZE]; ssize_t recvLen; cout << "\n----- 开始接收服务器响应 -----\n" << endl; while ((recvLen = recv(connfd, buffer, BUFFER_SIZE - 1, 0)) > 0) { // 确保字符串正确终止 buffer[recvLen] = '\0'; // 输出接收到的数据 cout << buffer; }
// 检查接收是否出现错误 if (recvLen == -1) { cerr << "\n接收数据时发生错误: " << strerror(errno) << endl; close(connfd); return 1; }
cout << "\n\n----- 服务器响应接收完毕 -----" << endl;
// 关闭连接 close(connfd); cout << "连接已关闭" << endl;
return 0; }
|