用socket发GET请求核心三步:解析域名并连接、构造含Host和\r\n的请求头并关闭写端、循环recv直至读完响应。需注意跨平台初始化、换行符、协议头及错误处理细节。

用 socket 发送 GET 请求,核心就三步
Windows 或 Linux 下用原生 socket 发 HTTP GET 请求,不依赖第三方库是可行的,但必须手动处理连接、构造请求头、读取响应。关键不是“能不能”,而是“别漏掉换行和协议细节”。
- 必须用
\r\n(回车+换行)结尾,单用\n服务器大概率返回400 Bad Request - 必须带
Host:头,HTTP/1.1 协议强制要求,否则很多服务(如 Nginx、Cloudflare)直接拒收 - 建议加
Connection: close,避免服务端保持长连接导致recv()阻塞或读不全 - 域名需先用
getaddrinfo()解析,不能直接传给connect();IPv4/IPv6 兼容写法比硬写AF_INET更稳妥
send() 后一定要 shutdown(SD_SEND)(Windows)或 shutdown(sockfd, SHUT_WR)(Linux)
很多人卡在“发了请求但 recv 没返回”,本质是 TCP 连接仍处于“可写”状态,服务端等你继续发数据。不主动关闭写端,服务端可能不发响应或延迟发。
- Windows 下用
shutdown(sockfd, SD_SEND),不是closesocket() - Linux 下对应
shutdown(sockfd, SHUT_WR) - 这一步之后再
recv(),才能让服务端明确知道请求结束,开始回包 - 忽略它,
recv()可能阻塞、超时,或只读到部分响应(比如只有 status line)
读响应时别假设一次 recv() 能读完
HTTP 响应可能分多次到达,尤其 Body 较大时。直接 recv(buf, sizeof(buf)-1, 0) 一次读,大概率截断。
- 先读状态行,解析出
Content-Length:或检测Transfer-Encoding: chunked - 若含
Content-Length: 1234,就循环recv()直到累计读够 1234 字节 - 若为
chunked,需实现 chunk 解析(每块以十六进制长度开头 +\r\n+ 数据 +\r\n),复杂度陡增——简单场景尽量避免 - 至少加个循环:while (bytes = recv(...)) > 0,直到返回 0(对端关闭)或 -1(错误)
跨平台编译前记得初始化和清理
Windows 和 Linux 的 socket 初始化差异极大,不处理会直接 crash 或 connect 失败。
立即学习“C++免费学习笔记(深入)”;
- Windows 必须调
WSAStartup(),且在main()开头;程序退出前调WSACleanup() - Linux 不需要初始化,但
close()替代closesocket() -
SOCKET类型在 Windows 是unsigned int,Linux 是int,混用会导致编译失败或运行异常 - 错误检查别只看
== -1:Windows 返回SOCKET_ERROR,Linux 才是-1;统一用if (sock == INVALID_SOCKET)(Windows)或if (sock (Linux)
Host 头——这些点漏一个,请求就静默失败。










