URL
URL:统一资源定位符,它是一种特殊类型的URI,包含了用于查找某个资源的足够的信息。
URL由三部分组成:资源类型、存放资源的主机域名、资源文件名。
URL的一般语法格式为:(带方括号[]的为可选项):
http://hostname[:port][path]
http表示通过http协议来定位网络资源,hostname表示合法的主机域名或IP地址。port指定一个端口号,为空则使用缺省端口80,path指定请求资源的路径,如果URL中没有给出path,那么浏览器会自动会加上“/”,表示web根目录。
如:
http://www.baidu.com
经过浏览器之后就会变成:
http://www.baidu.com/
带参的URL如下:
http://www.baidu.com/?a=10&b=20
其中“?”表示参数的开始,每个参数都是name=value的形式,每个参数之间以“&”分隔。
HTTP请求
http请求是由请求行、消息报头、空行、请求正文组成。
请求行:method、url、http协议版本
消息报头:名字、冒号、空格、值组成http消息报头(name: value)
空行:必须要有一个空行,以确定消息报头的长度(空行实际上也是一种避免粘包的策略,因为我们知道,第一行是请求行,从第二行开始一直到空行就是消息报头了)
请求正文:…
注: HTTP请求的格式至少要包含一个请求行和一个空行。
method:表示请求方法
- GET :请求获取Request-URl所标识的资源
- POST :在Request-URl所标识的资源后附加新的数据
- HEAD :请求获取由Request-URl所标识的资源的响应消息报头
- PUT :请求获取由Request-URl所标识的资源的响应消息报头
- DELETE :请求服务器删除Request-URl作为其标识
- TRACE :请求服务器或回送收到的请求信息,用于测试或诊断
- CONNECT :保留将来使用
- OPTIONS :请求查询服务器的性能,或者查询与资源相关的选项和需求
url:表示请求资源的路径,如果是GET方法的话,可以带有参数。它的值也就是URL中的path。如果是post的方法的话,它的参数在消息正文中。
HTTP响应
http响应是由状态行、消息报头、空行、响应正文组成。
状态行:http协议版本、状态码、状态码描述
消息报头:name: value
空行:
响应正文:…
状态码:
- 1xx:指示信息。表示请求已接受,继续处理
- 2xx:成功。表示请求被成功接收、理解、接受
- 3xx:重定向。要完成请求必须进行更进一步的操作
- 4xx:客户端错误。请求语法有错误,或请求无法实现
- 5xx:服务器端错误。服务器未能实现合法的请求
常见状态码:
200 OK //客户端请求成功
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Nto Found //请求资源不存在,也就是输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请
HTTP的特点
支持客户/服务器模式(c/s 或 b/s)
简单快速:客户向服务器请求服务的时候,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP服务器程序规模小,因而通信速度很快。
灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答之后即断开连接。采用这种方式可以减少传输时间。
无状态:HTTP协议是无状态协议。无状态是指协议对事物处理没有记忆能力。缺少状态的话意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次链接传送的数据量增大。另一方面,服务器不需要先前信息时它应答就比较快。
简单的HTTP服务器
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;
void PackageResponse(char http_resp[]){
int cur_len = 0;
const char* html = "<html><h2>hello</h2></html>";
cur_len += sprintf(http_resp, "HTTP/1.1 200 OK\n");
cur_len += sprintf(http_resp + cur_len, "Content-Length: %lu\n",strlen(html));
cur_len += sprintf(http_resp + cur_len, "\n");
cur_len += sprintf(http_resp + cur_len, "%s", html);
}
int main(int argc, char* argv[]){
if(argc != 3){
printf("Usage ./server [ip] [port]\n");
return 1;
}
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd < 0){
perror("socket");
return 1;
}
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2]));
int ret = bind(fd, (sockaddr*)&addr, sizeof(addr));
if(ret < 0){
perror("bind");
return 1;
}
ret = listen(fd, 5);
if(ret < 0){
perror("listen");
return 1;
}
while(1){
sockaddr_in peer_addr;
socklen_t len = sizeof(peer_addr);
int new_fd = accept(fd, (sockaddr*)&peer_addr, &len);
if(new_fd < 0){
perror("accept");
continue;
}
char buf[100 * 1024] = {0};
ssize_t read_size = read(new_fd, buf, sizeof(buf) - 1);
if(read_size < 0){
perror("read");
close(new_fd);
continue;
}
if(read_size == 0){
close(new_fd);
continue;
}
buf[read_size] = '\0';
printf("[Request]\n%s\n", buf);
char http_resp[100 * 1024] = {0};
PackageResponse(http_resp);
write(new_fd, http_resp, strlen(http_resp));
close(new_fd);
}
return 0;
}
最后的效果是在网页上显示hello