什么是http协议:基于tcp的超文本传输协议
http编程模型(B/S):
1.建立tcp连接
1.1 创建socket
1.2 设置socket
1.3 绑定
1.4 监听
2.等待客户端连接服务器 accept
3.接收客户端发来的请求并解析
4.制作响应
5.响应发送客户端
http特性:
1.支持C/S、B/S模式
2.简单且快速
3.灵活:可以传输任意类型数据
4.可以无连接:每次tcp处理一个(1.1版本)或多个(2.0版本以上)请求
5.无状态:协议对业务的处理没有记忆能力
优点:快速、简单、方便、效率高
缺点:明文传输数据,不是很可靠、不是很稳定
写一个通过http路径访问网页:
文件准备:
随便一张图片用于在网页中展示
网页html文件
方便编译运行的makefile文件(可以没有)
代码文件
index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>httpServer</title>
</head>
<body>
<h1>day14_httpServer</h1>
<img src="./1.jpg" alt="">
</body>
</html>
server.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
// 创建监听套接字
int create_listenfd();
// 处理请求
void handle_request(int clientfd);
int main()
{
// 1.建立tcp连接
int serverfd = create_listenfd();
while (1)
{
// 2.接收客户端连接
int clientfd = accept(serverfd, NULL, NULL);
if (-1 == clientfd)
{
printf("accept失败%m\n");
continue;
}
// 3.处理客户端发来的请求
handle_request(clientfd);
}
return 0;
}
int create_listenfd()
{
printf("------start of socket------\n");
// 1.1 创建socket
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sfd)
{
printf("create_listenfd中创建socket失败%m\n");
return -1;
}
printf("创建socket成功\n");
// 1.2 设置socket
int n = 1;
int r = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
if (-1 == r)
{
printf("create_listenfd中setsockopt失败%m\n");
return -1;
}
printf("设置socket成功\n");
// 1.3 绑定
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
addr.sin_addr.s_addr = INADDR_ANY; // 监听任意地址
r = bind(sfd, (struct sockaddr *)&addr, sizeof(addr));
if (-1 == r)
{
printf("create_listenfd中bind失败%m\n");
return -1;
}
printf("绑定成功\n");
// 1.4 监听
r = listen(sfd, 999999);
if (-1 == r)
{
printf("create_listenfd中listen失败%m\n");
return -1;
}
printf("监听成功\n");
printf("------end of socket------\n");
return sfd;
}
void handle_request(int clientfd)
{
// 接收请求
char buff[1024 * 1024] = {0};
int nread = read(clientfd, buff, sizeof(buff)); // 也可以用recv
if (-1 == nread)
{
printf("read失败%m\n");
return;
}
// printf("%d: %s\n",nread,buff);
// 解析请求
// 获取文件名
char filename[20] = {0};
sscanf(buff, "GET /%s", filename);
printf("文件名:%s\n", filename);
// 根据文件名获取mime文件类
// 用来放到响应头中,告诉浏览器返回的是什么类型的文件
char *mime = NULL;
if (strstr(filename, ".html"))
{
mime = "text/html"; // 文本类型
}
else if (strstr(filename, ".jpg"))
{
mime = "image/jpg"; // jpeg图片类型
}
// 制作响应
char response[1024 * 1024] = {0};
// 响应头
//这里不直接用sprintf是因为sprintf会报warning
const char* header = "HTTP/1.1 200 OK\r\nContent-Type:%s\r\n\r\n";
snprintf(response, sizeof(response), header, mime);
int header_len = strlen(response);
// 响应体
int fd = open(filename, O_RDONLY);
if(-1 == fd)
{
printf("open %s 失败%m\n",filename);
return;
}
int file_len = read(fd, response + header_len, sizeof(response) - header_len);
// 发送响应
write(clientfd, response, header_len + file_len);
close(fd);
}
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » Linux从入门到开发实战(C/C++)Day14-http协议
发表评论 取消回复