当前位置: 首页 > news >正文

报文头 和fprint的说明 day45

三:send_head报文头

给浏览器一个校准的头,不依靠浏览器的自身纠错能力

头部信息基本都是固定的,关注报文的响应报文,而不是请求报文

#include <asm-generic/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>
typedef struct sockaddr*(SA);
typedef enum
{FILE_HTML,FILE_PNG,FILE_JPG
} FILE_TYPE;
int send_head(int conn, char* filename, FILE_TYPE type)
{struct stat st;//用于获取文件大小int ret = stat(filename, &st);if (-1 == ret){// perror("");fprintf(stderr, "stat error , %s ,filename:%s\n", strerror(errno),filename);return 1;}char* httm_cmd[6] = {NULL};char typebuf[100] = {0};char lengbuf[50] = {0};//响应行  表是可以正常响应httm_cmd[0] = "HTTP/1.1 200 OK\r\n";   //200正常响应,  //状态码(Status-Code)都是三位数字的,分为5大类共33种。//例如,1xx表示通知信息的,如请求收到了或正在进行处理。//2xx表示成功,如接受或知道了。//3xx表示重定向,如要完成请求还必须采取进一步的行动。  如304 比如照片无法正常缓存//4xx表示客户的差错,如请求中有错误的语法或不能完成。  如404 :意思是找不到//5xx表示服务器的差错,如服务器失效无法完成请求。httm_cmd[1] = "Server: Tengine\r\n";  // web server名字httm_cmd[2] = typebuf; // 告知对方浏览器,发送的文件的类型switch (type){case FILE_HTML://对应是那种类型,是活的sprintf(typebuf, "Content-Type: text/html; charset=UTF-8\r\n");break;case FILE_JPG:sprintf(typebuf, "content-type: image/jpeg\r\n");break;case FILE_PNG:sprintf(typebuf, "Content-Type: image/png\r\n");break;}// 告知对方浏览器,资源的大小httm_cmd[3] = lengbuf;sprintf(lengbuf, "Content-Length: %lu\r\n", st.st_size);//连接方式 长连接   			closed(短链接)httm_cmd[4] = "Connection: keep-alive\r\n";//资源的过期时间httm_cmd[5] = "Date: Wed, 30 Jul 2025 03:21:39 GMT\r\n\r\n";for (int i = 0; i < 6; ++i){send(conn, httm_cmd[i], strlen(httm_cmd[i]), 0);}return 0;
}int send_file(int conn, char* filename, FILE_TYPE type)
{send_head(conn, filename, type);int fd = open(filename, O_RDONLY);if (-1 == fd){perror("open");return 1;}while (1){char buf[1024] = {0};int ret = read(fd, buf, sizeof(buf));if (ret <= 0){break;}send(conn, buf, ret, 0);}close(fd);return 0;
}
int main(int argc, char** argv)
{//监听套接字 功能检测是否有客户端 连连接服务器int listfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == listfd){perror("socket");return 1;}int on = 1;// man 7 socket  地址和断开可以多次绑定,这两个选项仅在测试时开启。setsockopt(listfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));setsockopt(listfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));// man 7 ipstruct sockaddr_in ser, cli;bzero(&ser, sizeof(ser));bzero(&cli, sizeof(cli));ser.sin_family = AF_INET;// sudo ./sser.sin_port = htons(80);// 代表本机地址  外部客户端可以连接到服务器ser.sin_addr.s_addr = INADDR_ANY;int ret = bind(listfd, (SA)&ser, sizeof(ser));if (-1 == ret){perror("bind");return 1;}// 同一时刻可以服务器建立连接的排队数listen(listfd, 3);socklen_t len = sizeof(cli);while (1){// 1 建立连接int conn = accept(listfd, (SA)&cli, &len);if (-1 == conn){perror("accept");close(conn);continue;}char buf[1024] = {0};// 2接收客户端的请求int rec_ret = recv(conn, buf, sizeof(buf), 0);if (rec_ret <= 0){close(conn);continue;}printf("%s\n", buf);// 3 处理请求+回应// GET / HTTP/1.1\r\nchar* method = strtok(buf, " ");//统一资源定为符char* url = strtok(NULL, " ");char* ver = strtok(NULL, "\r");if (0 == strcmp(url, "/")){send_file(conn, "./02.html",FILE_HTML);  // login}else if (0 == strcmp(url, "/favicon.ico")){send_file(conn, "./2.png",FILE_PNG);  // login}//  /login?username=zhangsan&userpw=123else if (0 == strncmp(url, "/login", strlen("/login"))){char* name = strchr(url, '=');name += 1;char* end = strchr(name, '&');*end = '\0';char* pw = strchr(end + 1, '=');pw += 1;if (0 == strcmp(name, "zhangsan") && 0 == strcmp(pw, "123")){//账号 ,密码正确 发送功能页面send_file(conn, "./01.html",FILE_HTML);}else{//账号密码错误, 发送密码错误页面send_file(conn, "./03.html",FILE_HTML);}}else if (strlen(url) > 4 &&0 == strcmp(&url[strlen(url) - 3], "png"))  // /100.png{send_file(conn, url + 1,FILE_PNG);}else if (strlen(url) > 4 &&0 == strcmp(&url[strlen(url) - 3], "jpg"))  // /100.png{send_file(conn, url + 1,FILE_JPG);}// 4 断开连接close(conn);}close(listfd);// system("pause");return 0;
}

五:关于项目中fprintf的一些说明

明白了!你的问题核心是:

fprintf(fp, " <td>%s</td>\n", result[i]); 中,%s 是怎么和 result[i] 对应起来的?
它为什么不需要你手动逐字符扫过去(像 fgetc() 那样)?是否可以详细解释一下 fprintf() 的工作原理?

一:fprintf() 函数详解

什么是 fprintf()

  • fprintf() 是 C 语言中的格式化输出函数,用于将格式化的数据写入指定文件。
  • 它的工作原理和 printf() 类似,但输出目标不同:
    • printf() 输出到标准输出(屏幕);
    • fprintf(fp, ...) 输出到文件指针 fp 指定的文件中。
c复制代码
int fprintf(FILE *stream, const char *format, ...);
  • stream:文件指针,如 fp
  • format:格式字符串;
  • ...:对应格式字符串中 % 占位符的参数。

二:fprintf() 的工作原理

格式字符串解析

fprintf() 会逐字符解析格式字符串:

c复制代码
fprintf(fp, "    <td>%s</td>\n", result[i]);
  1. 遇到普通字符,如空格、<, t, d 等,会直接写入文件。

  2. 遇到 %s,会自动用 result[i] 的内容替换。

  3. 整行内容最终写入文件,如:

    css复制代码
    <td>hello</td>
    

自动处理字符串输出

  • %s 表示输出一个字符串,fprintf() 会从传入的 char* 地址开始,直到遇到 \0 结束。
  • 无需手动逐字符写入或格式拼接。

三:与其他写入函数的对比

函数用途优点缺点
fprintf()格式化写入文件自动格式化、最灵活相对底层控制力弱
fputs()写入字符串直接写字符串不支持格式替换
fputc()写入单字符精确控制需要逐字符拼接
fgetc()读取单字符用于读取,不写入与写操作无关

四:常用格式符号

格式符含义示例值
%s字符串"hello"
%d十进制整数123
%f浮点数3.14
%c单个字符'A'
%%百分号本身%
http://www.dtcms.com/a/308108.html

相关文章:

  • 前端-移动Web-day2
  • 极客大挑战2020(部分wp)
  • 【1】数据可视化分析方法
  • 【go】 if条件控制语句
  • 渗透RCE
  • php在使用 composer 安装时报错集合
  • Jmeter 命令行压测、HTML 报告、Jenkins 配置目录
  • 材质:3D渲染的隐形支柱
  • 第二篇:Three.js核心三要素:场景、相机、渲染器
  • Linux网络-------3.应⽤层协议HTTP
  • 【运维基础】Linux 进程调度管理
  • 异步I/O和同步I/O
  • USRP捕获手机/路由器数据传输信号波形(下)
  • 金融专题|某跨境支付机构:以榫卯企业云平台 VPC 功能保障业务主体安全
  • 文档识别算法-文字识别接口-表格还原-图表文字识别API
  • HCIA-Datacom认证笔记:IP路由基础——核心概念与路由分类
  • Amazon Aurora MySQL 8.0 完整指南
  • 一些利用AIOps工具进行云原生技术持续创新的成功案例
  • Python 元编程实战:动态属性与数据结构转换技巧
  • Pycaita二次开发基础代码解析:曲面法线生成、零件加载与材料应用
  • 基于LSTM-GRU混合网络的动态解析:美联储维稳政策与黄金单日跌1.5%的非线性关联
  • AI陪伴的发展现状
  • STM32——HAL 库MDK工程创建
  • 2000-2024年中国1KM分辨率年度植被指数(NDVI、EVI)数据集
  • 万物都有属于自己的律动
  • 公路坑槽检测分析原理和思路
  • 嵌入式开发学习———Linux环境下IO进程线程学习(一)
  • 【0基础PS】Photoshop (PS) 理论知识
  • linux线程互斥和同步
  • 操作系统系统面试常问(内存、快表、相关知识)