news 2026/9/3 15:27:41

C++综合实战:网络编程入门与HTTP客户端

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++综合实战:网络编程入门与HTTP客户端

本文是 C++ 系列教程的第 29 篇。上一篇完成了面向对象图书管理系统,本篇实战网络编程:Socket 基础与 TCP 通信、HTTP 协议解析、迷你 HTTP 客户端实现与简易服务器,覆盖 9 个完整示例代码。

一、网络编程基础

1.1 客户端/服务器模型与 Socket

网络通信的核心模型:服务器监听端口等待连接,客户端主动发起连接。**Socket(套接字)**是操作系统提供的网络编程接口,屏蔽底层协议细节:

客户端 服务器 | | |---- connect() -------->| 监听 listen() | | 接受 accept() |<-- send/recv 数据 ---->| | | |---- close() ---------->| close()

TCP 提供可靠、有序、面向连接的字节流传输,HTTP、FTP、SSH 等协议都建立在 TCP 之上。

1.2 TCP 客户端完整示例(Windows + Linux 通用思路)

// tcp_client.cpp —— 简易 TCP 客户端#include<iostream>#include<cstring>usingnamespacestd;// 说明:Windows 用 Winsock,Linux 用 POSIX socket,头文件不同。// 为便于演示,这里给出 Linux/POSIX 版本核心代码。#include<sys/socket.h>#include<arpa/inet.h>#include<unistd.h>intmain(){intsock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){cerr<<"创建 socket 失败"<<endl;return1;}sockaddr_in server{};server.sin_family=AF_INET;server.sin_port=htons(8080);inet_pton(AF_INET,"127.0.0.1",&server.sin_addr);if(connect(sock,(sockaddr*)&server,sizeof(server))<0){cerr<<"连接失败"<<endl;return1;}cout<<"已连接服务器!"<<endl;constchar*msg="Hello Server!";send(sock,msg,strlen(msg),0);charbuffer[1024]={};intn=recv(sock,buffer,sizeof(buffer),0);if(n>0)cout<<"收到回复: "<<buffer<<endl;close(sock);return0;}

关键步骤:socket()创建套接字 →connect()连接服务器 →send()/recv()收发数据 →close()关闭。htons把端口转为网络字节序。

二、HTTP 协议

2.1 HTTP 请求与响应格式

HTTP 是请求-响应模型:客户端发请求,服务器回响应。请求由「请求行 + 请求头 + 空行 + 请求体」组成

GET /index.html HTTP/1.1 ← 请求行:方法 路径 协议版本 Host: www.example.com ← 请求头(键: 值) User-Agent: MyCppClient/1.0 Accept: */* ← 空行(必须) (请求体,GET 通常为空)

响应由「状态行 + 响应头 + 空行 + 响应体」组成:

HTTP/1.1 200 OK ← 状态行:版本 状态码 原因短语 Content-Type: text/html Content-Length: 1256 <html><body>...</body></html> ← 响应体

2.2 常用 HTTP 方法与状态码

方法用途状态码含义
GET获取资源200 OK成功
POST提交数据201 Created已创建
PUT更新资源301 Moved永久重定向
DELETE删除资源404 Not Found资源不存在
HEAD只取响应头500 Internal Server Error服务器错误

三、迷你 HTTP 客户端

3.1 构造请求并解析响应

写一个简化版 HTTP 客户端:连接服务器、发送 GET 请求、读取并解析响应头与响应体:

// mini_http_client.cpp —— 迷你 HTTP 客户端(Linux 版核心逻辑)#include<iostream>#include<string>#include<cstring>usingnamespacestd;#include<sys/socket.h>#include<arpa/inet.h>#include<unistd.h>// 解析响应头中的 Content-LengthintextractContentLength(conststring&header){size_t pos=header.find("Content-Length:");if(pos==string::npos)return-1;pos+=15;// 跳过 "Content-Length: "size_t end=header.find("\r\n",pos);returnstoi(header.substr(pos,end-pos));}intmain(){intsock=socket(AF_INET,SOCK_STREAM,0);sockaddr_in server{};server.sin_family=AF_INET;server.sin_port=htons(80);// HTTP 默认端口inet_pton(AF_INET,"93.184.216.34",&server.sin_addr);// example.comif(connect(sock,(sockaddr*)&server,sizeof(server))<0){cerr<<"连接失败"<<endl;return1;}// 构造 GET 请求string request="GET / HTTP/1.1\r\n""Host: example.com\r\n""User-Agent: MiniCppClient/1.0\r\n""Connection: close\r\n"// 响应后关闭连接"\r\n";send(sock,request.c_str(),request.size(),0);// 读取响应string response;charbuffe r[4096];intn;while((n=recv(sock,buffer,sizeof(buffer),0))>0){response.append(buffer,n);}close(sock);// 分离响应头与响应体size_t headerEnd=response.find("\r\n\r\n");string header=response.substr(0,headerEnd);string body=response.substr(headerEnd+4);cout<<"===== 状态行 ====="<<endl;cout<<header.substr(0,header.find("\r\n"))<<endl;cout<<"===== 响应体前 200 字符 ====="<<endl;cout<<body.substr(0,200)<<endl;intcontentLen=extractContentLength(header);cout<<"Content-Length: "<<contentLen<<"(实际收到 "<<body.size()<<" 字节)"<<endl;return0;}

Connection: close告诉服务器响应后关闭连接,客户端循环recv直到收到 0 字节即响应结束。

3.2 用系统命令快速验证

# 命令行验证 HTTP(Linux/macOS)curl-vhttp://example.com/curl-Ihttp://example.com/# 只取响应头# Windows PowerShellInvoke-WebRequest-Urihttp://example.com/|Select-Object-ExpandPropertyContent

curl对照自己实现的客户端输出,能直观确认请求格式是否正确。

四、简易 TCP 服务器

4.1 单线程服务器

// tcp_server.cpp —— 简易 TCP 服务器(Linux 版)#include<iostream>#include<cstring>usingnamespacestd;#include<sys/socket.h>#include<arpa/inet.h>#include<unistd.h>intmain(){intserver=socket(AF_INET,SOCK_STREAM,0);// 允许端口复用(避免 TIME_WAIT 导致 bind 失败)intopt=1;setsockopt(server,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));sockaddr_in addr{};addr.sin_family=AF_INET;addr.sin_addr.s_addr=INADDR_ANY;// 监听所有网卡addr.sin_port=htons(8080);bind(server,(sockaddr*)&addr,sizeof(addr));listen(server,5);// 最大等待队列 5cout<<"服务器监听 8080 端口..."<<endl;sockaddr_in client{};socklen_t len=sizeof(client);intconn=accept(server,(sockaddr*)&client,&len);cout<<"客户端已连接!"<<endl;charbuffer[1024]={};intn=recv(conn,buffer,sizeof(buffer),0);if(n>0){cout<<"收到: "<<buffer<<endl;constchar*reply="Hello from server!";send(conn,reply,strlen(reply),0);}close(conn);close(server);return0;}

服务器四步:socket()bind()绑定端口 →listen()开始监听 →accept()接受连接。之后与客户端收发数据。

4.2 简易 HTTP 服务器

把响应改为 HTTP 格式,就是一个迷你 Web 服务器:

// mini_http_server.cpp —— 返回固定 HTML 页面的 HTTP 服务器#include<iostream>#include<cstring>usingnamespacestd;#include<sys/socket.h>#include<arpa/inet.h>#include<unistd.h>intmain(){intserver=socket(AF_INET,SOCK_STREAM,0);intopt=1;setsockopt(server,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));sockaddr_in addr{};addr.sin_family=AF_INET;addr.sin_addr.s_addr=INADDR_ANY;addr.sin_port=htons(8080);bind(server,(sockaddr*)&addr,sizeof(addr));listen(server,5);cout<<"HTTP 服务器: http://127.0.0.1:8080/"<<endl;while(true){// 循环接受多个客户端sockaddr_in client{};socklen_t len=sizeof(client);intconn=accept(server,(sockaddr*)&client,&len);charbuffer[4096]={};recv(c onn,buffer,sizeof(buffer),0);// 读取请求(此处忽略内容)string body="<html><body><h1>Hello C++!</h1>""<p>这是一个 C++ HTTP 服务器</p></body></html>";string response="HTTP/1.1 200 OK\r\n""Content-Type: text/html; charset=utf-8\r\n""Content-Length: "+to_string(body.size())+"\r\n""Connection: close\r\n""\r\n"+body;send(conn,response.c_str(),response.size(),0);close(conn);}close(server);return0;}

浏览器访问http://127.0.0.1:8080/即可看到返回的页面。Content-Length必须与实际 body 字节数一致,否则浏览器可能显示不完整。

五、实战:带参数的 HTTP 请求

5.1 GET 带查询参数

// http_get_with_query.cpp —— 带查询参数的 GET(核心片段)#include<iostream>#include<string>usingnamespacestd;#include<sys/socket.h>#include<arpa/inet.h>#include<unistd.h>// URL 编码(简单版):空格转 %20stringurlEncode(conststring&s){string result;for(charc:s){if(c==' ')result+="%20";elseresult+=c;}returnresult;}intmain(){string keyword="C++ 教程";string path="/search?q="+urlEncode(keyword);string request="GET "+path+" HTTP/1.1\r\n""Host: example.com\r\n""Connection: close\r\n""\r\n";cout<<"发送请求:"<<endl;cout<<request<<endl;cout<<"(完整客户端逻辑同 3.1 节,此处演示请求构造)"<<endl;return0;}

查询参数放在?之后、&分隔多个键值对;特殊字符(空格、中文)需 URL 编码。

5.2 常见问题排查

问题可能原因排查方法
连接失败端口/地址错误、服务器未启动`netstat -an
响应为空请求格式错误、未发空行用 curl 对照请求文本
中文乱码编码未指定响应头加charset=utf-8
Content-Length 不匹配body 计算错误body.size()而不是手写数字
端口占用前次连接未释放SO_REUSEADDR或等 TIME_WAIT 结束

总结

本篇讲解了 C++ 网络编程入门:Socket 基础(客户端/服务器模型与 TCP 通信四步)、HTTP 协议(请求/响应格式、方法、状态码)、迷你 HTTP 客户端(构造 GET 请求、解析响应头与 Content-Length)、简易 TCP/HTTP 服务器(bind/listen/accept 循环)与带查询参数的请求构造及常见问题排查。建议用curl对照验证,并在本机 8080 端口跑通客户端-服务器闭环。

下一篇将是系列终章C++ 综合实战:数据结构与算法实现及系列总结(手写容器、排序算法与 30 篇回顾),敬请期待!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 15:25:13

布鲁可擎天柱肩膀安装DIY攻略:三种方式与变形收纳调整

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 15:24:30

从CyberOne亮相IFA看人形机器人技术栈:ROS 2与仿真实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 15:22:53

Grok Voice 2.0语音理解模型:从ASR到智能交互的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 15:22:06

4步加速LoRA实战:ComfyUI + MiniMax H3 工作流优化

最近看到一条标题&#xff1a;4步加速V3 lora来了&#xff0c;MiniMax H3 超级加速&#xff0c;无需任何 ComfyUI 插件。初看很像标题党&#xff0c;但如果你已经在 ComfyUI 里手动调过采样步数&#xff0c;就会知道“让模型少迭代几次”确实是本地生成工作流中最值得优化的方向…

作者头像 李华