sprintf,sscanf,fread,fwrite

本文详细介绍了C语言中的sprintf和sscanf函数的使用方法,通过实例演示了如何利用这些函数进行字符串的数据写入和读取。此外,还介绍了fread和fwrite函数的基本用法,用于实现文件的二进制数据读写。

sprintf函数

先来看一下msdn中对这个函数的定义;
Write formatted data to a string.(写格式化数据到一个字符串)
int sprintf( char *buffer, const char *format [, argument] … )
它的参数有一个字符串和可变参数
代码演示如下

#include<stdio.h>
struct S
{
    char name[20];
    int age;
    char sex[5];
};

int main()
{
    char buf[100] = {0};
    struct S s = {"zhangsan", 20, "男"};
    sprintf(buf,"%s %d %s",s.name, s.age, s.sex);
    printf("%s",buf);
    system("pause");
    return 0;
}

执行上的代码,屏幕上会输出zhangsan 20 男

sscanf

Read formatted data from a string.(从一个字符串中读取格式化数据)
int sscanf( const char *buffer, const char *format [, argument ] … );
参是与sprintf相同

代码演示

#include<stdio.h>
struct S
{
    char name[20];
    int age;
    char sex[5];
};

int main()
{
    struct S tmp = {0};
    char buf[100] = {0};
    struct S s = {"zhangsan", 20, "男"};
    sprintf(buf,"%s %d %s",s.name, s.age, s.sex);
    printf("%s\n",buf);
    sscanf(buf,"%s %d %s", tmp.name, &(tmp.age), tmp.sex);
    printf("%s %d %s\m", tmp.name, tmp.age, tmp.sex);
    system("pause");
    return 0;
}

fread和fwrite

这两个函数是以二进制的形式从流中读取和写入数据。
fwrite的参数
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream )
它的参数是要写的源数据,源数据的大小,每次要写入的个数,要写入的目标。

#include<stdio.h>
struct S
{
    char name[20];
    int age;
    char sex[5];
};
int main()
{
    struct S s = {"wangwu", 20, "女"};
    FILE* pf = fopen("test.q", "wb");
    fwrite(&s, sizeof(s), 1, pf);
    fclose(pf);
    pf = NULL;
    return 0;
}

fread和fwrite相反,是从流中以二进制的形式读取数据
参数
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

#include<stdio.h>
struct S
{
    char name[20];
    int age;
    char sex[5];
};
int main()
{
    struct S s = {0};
    FILE* pf = fopen("test.q", "bb");
    fread(&s, sizeof(s), 1, pf);
    printf("%s %d %s\n",s.name, s.age, s.sex);
    fclose(pf);
    pf = NULL;
    return 0;
}
请优化下这段代码“#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <pthread.h>/*监听端口*/#define PORT 80/*指定系统允许处于等待接受连接状态的连接的最大数量*/#define BACKLOG 10/*网站根目录*/#define ROOT_DIR "./source"// 获取文件类型const char *get_mime_type(const char *filename) { const char *ext = strrchr(filename, '.'); if (!ext) { return "application/octet-stream"; } if (strcmp(ext, ".html") == 0 || strcmp(ext, ".htm") == 0) { return "text/html"; } if (strcmp(ext, ".txt") == 0) { return "text/plain"; } if (strcmp(ext, ".css") == 0) { return "text/css"; } if (strcmp(ext, ".js") == 0) { return "application/javascript"; } if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0) { return "image/jpeg"; } if (strcmp(ext, ".png") == 0) { return "image/png"; } if (strcmp(ext, ".gif") == 0) { return "image/gif"; } if (strcmp(ext, ".pdf") == 0) { return "application/pdf"; } if (strcmp(ext, ".zip") == 0) { return "application/zip"; } return "application/octet-stream";}/*处理http请求*/void *handle_request(void *p_client_socket) { int client_socket = *((int *)p_client_socket); free(p_client_socket); char buffer[4096]; /*从代表客户端的文件中读取数据*/ int bytes_read = read(client_socket, buffer, sizeof(buffer) - 1); /*保证最后一个字符一定是\0,字符串不会溢出*/ buffer[bytes_read] = '\0'; /*从缓冲区读入:请求方法,请求路径,协议*/ char method[10], path[1024], protocol[10]; sscanf(buffer, "%s %s %s", method, path, protocol); /*响应头和响应内容*/ char response[4096]; char content[4096]; int content_length = 0; /*拼接完整路径,/属于默认情况,这里的主页为Index.html,需要注意*/ char full_path[1024]; sprintf(full_path, "%s%s", ROOT_DIR, strcmp(path, "/") == 0 ? "/Index.html" : path); /*处理请求 请求如果不是PUT和DELETE,要操作文件,权限只能是读*/ FILE *file = NULL; if (strcasecmp(method, "PUT") != 0 && strcasecmp(method, "DELETE") != 0) { file = fopen(full_path, "r"); } /*具体的对每个请求方法的处理策略*/ if (strcasecmp(method, "GET") == 0) { if (file) { /*计算文件长度*/ fseek(file, 0, SEEK_END); content_length = ftell(file); rewind(file); printf("GET file from %s\n",full_path); /*获取文件类型*/ const char *mime_type = get_mime_type(full_path); /*格式输出到响应头*/ sprintf(response, "HTTP/1.0 200 OK\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n", mime_type, content_length); /*发送响应头*/ if (write(client_socket, response, strlen(response)) == -1) { perror("response_head"); close(client_socket); return; } /*循环保证内容发送完毕*/ while ((content_length = fread(content, 1, sizeof(content), file)) > 0) { if (write(client_socket, content, content_length) == -1) { perror("response_content"); close(client_socket); return; } } } else { /*未找到文件*/ char *error_message = "404 Not Found"; sprintf(response, "HTTP/1.0 404 Not Found\r\nContent-Length: %zu\r\n\r\n%s", strlen(error_message), error_message); /*发送响应头*/ if (write(client_socket, response, strlen(response)) == -1) { perror("response_head"); close(client_socket); return; } } } else if (strcasecmp(method, "HEAD") == 0) { if (file) { /*不读取文件计算文件长度的一种做法,搭配fseek和ftell*/ fseek(file, 0, SEEK_END); content_length = ftell(file); printf("HEAD %s\n", file); sprintf(response, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n", content_length); } else { char *error_message = "404 Not Found"; sprintf(response, "HTTP/1.0 404 Not Found\r\nContent-Length: %zu\r\n\r\n", strlen(error_message)); } /*发送响应头*/ if (write(client_socket, response, strlen(response)) == -1) { perror("response_head"); close(client_socket); return; } } else if (strcasecmp(method, "PUT") == 0) { char *content_length_str = strstr(buffer, "Content-Length:"); if (content_length_str) { sscanf(content_length_str, "Content-Length: %d", &content_length); } int content_read = 0; /*PUT涉及到新建文件,所以要给写权限*/ file = fopen(full_path, "w"); if (file) { printf("PUT %s\n", file); /*从buffer中定位到请求体开始的位置*/ char *body = strstr(buffer, "\r\n\r\n") + 4; //把字符串开头偏移到文件内容开头,这也就是为什么要有一个空行分割请求头和请求体的意义 int body_length = bytes_read - (body - buffer); // 已经读取的请求体长度 if (body_length < content_length) { /*如果已读取的请求体长度小于Content-Length,继续读取 将已经在buffer中的请求体部分写入文件*/ fwrite(body, 1, body_length, file); /*计算还需从客户端读取的数据量*/ int to_read = content_length - body_length; /*还有数据需要读取时,进入循环*/ while (to_read > 0) { /*确定一次读取的数据量,不超过content数组的大小,也不超过剩余需要读取的数据量*/ int max_read_size = sizeof(content); if (max_read_size > to_read) { max_read_size = to_read; } /*从客户端读取数据*/ content_read = read(client_socket, content, max_read_size); /*如果从客户端读到了数据*/ if (content_read > 0) { /*将读取的数据写入文件*/ fwrite(content, 1, content_read, file); /*减少剩余需要读取的数据量*/ to_read -= content_read; } else { /*如果没有读到数据(content_read <= 0),则跳出循环 这可能是因为客户端已关闭连接,或出现读取错误*/ break; } } } else { /*已经读取的部分足够长,直接写入*/ fwrite(body, 1, content_length, file); } sprintf(response, "HTTP/1.0 201 Created\r\n\r\n"); } else { sprintf(response, "HTTP/1.0 500 Internal Server Error\r\n\r\n"); } /*发送响应头*/ if (write(client_socket, response, strlen(response)) == -1) { perror("response_head"); close(client_socket); return; } } else if (strcasecmp(method, "DELETE") == 0) { printf("DELETE"); if (remove(full_path) == 0) { sprintf(response, "HTTP/1.0 200 OK\r\n\r\n"); } else { sprintf(response, "HTTP/1.0 404 Not Found\r\n\r\n"); } /*发送响应头*/ if (write(client_socket, response, strlen(response)) == -1) { perror("response_head"); close(client_socket); return; } } else if (strcasecmp(method, "POST") == 0) { printf("POST\n"); /*解析content-length*/ char *content_length_str = strstr(buffer, "Content-Length:"); if (!content_length_str) { char *error_message = "HTTP/1.0 411 Length Required\r\n\r\n"; write(client_socket, error_message, strlen(error_message)); close(client_socket); return; } sscanf(content_length_str, "Content-Length: %d", &content_length); /*定位请求体起始位置*/ char *body_start = strstr(buffer, "\r\n\r\n"); if (!body_start) { char *error_message = "HTTP/1.0 400 Bad Request\r\n\r\n"; write(client_socket, error_message, strlen(error_message)); close(client_socket); return; } body_start += 4; /*跳过空行*/ /*读取剩余请求体数据*/ int body_read = bytes_read - (body_start - buffer); char *body_buffer = malloc(content_length + 1); memcpy(body_buffer, body_start, body_read); /*继续读取未完整接收的数据*/ int remaining = content_length - body_read; while (remaining > 0) { int n = read(client_socket, body_buffer + body_read, remaining); if (n <= 0) break; body_read += n; remaining -= n; } body_buffer[content_length] = '\0'; /*处理请求体(保存到user.txt)*/ FILE *post_file = fopen(full_path, "wb"); if (post_file) { fwrite(body_buffer, 1, content_length, post_file); fclose(post_file); sprintf(response, "HTTP/1.0 200 OK\r\n\r\nFile saved: %s", full_path); } else { printf("write fail"); sprintf(response, "HTTP/1.0 500 Internal Server Error\r\n\r\n"); } /*发送响应*/ write(client_socket, response, strlen(response)); free(body_buffer); } else { /*没实现的请求方法就返回没实现的状态码501*/ sprintf(response, "HTTP/1.0 501 Not Implemented\r\n\r\n"); /*发送响应头*/ if (write(client_socket, response, strlen(response)) == -1) { perror("response_head"); close(client_socket); return; } } if (file) { //这里统一关闭文件 fclose(file); }}int main() { /*创建服务器套接字*/ /*AF_INET表示IPv4,SOCK_STREAM表示TCP 创建用来TCP通信的socket,创建成功返回非负数 */ int server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } /*设置SO_REUSEADDR选项,避免端口占用*/ int opt = 1; if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { perror("setsockopt failed"); close(server_socket); exit(EXIT_FAILURE); } /*绑定地址和端口*/ /*struct sockaddr_in是通用的IPv4套接字地址结构,存储关于套接字的所有地址信息*/ struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; /*使用IPv4协议*/ server_addr.sin_addr.s_addr = INADDR_ANY; /*监听本地所有网络接口*/ server_addr.sin_port = htons(PORT); /*端口号,使用网络字节序*/ /*将套接字描述符绑定到指定地址和端口上*/ if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind failed"); close(server_socket); exit(EXIT_FAILURE); } /*开始监听*/ if (listen(server_socket, BACKLOG) < 0) { perror("listen failed"); close(server_socket); exit(EXIT_FAILURE); } int client_socket; struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); printf("Server running on port %d, serving files from %s\n", PORT, ROOT_DIR); printf("Open http://localhost in your browser\n"); /*多线程并发*/ while (1) { /*客户端连接,通过对这个套接字的读写来接收和发送数据*/ struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len); if (client_socket < 0) { perror("accept failed"); continue; } pthread_t thread_id; int *pclient = malloc(sizeof(int)); *pclient = client_socket; //创建新线程 pthread_create(&thread_id, NULL, handle_request, pclient); //将线程设置为分离状态,执行完毕会自己回收所有资源 pthread_detach(thread_id); /*这里并没有使用互斥锁*/ } close(server_socket); return 0;}”中的多线程部分,在浏览其打开多个网页后程序可能会自动停止。
最新发布
08-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值