应用层(重要写代码)
协议:是双方的一种约定
报头:
HTTP协议(超文本传输协议)
URL:通俗来说网址
urlencode:特殊字符的编码
urldecode:编码之后的解码
http抓包
http常见Header:
-
Cookie:保存身份标识,避免重复登录,存字符串,保存数据有限(4K)
-
POST:有Body
-
GET:没Body
-
referer:当前页面是从哪个页面跳转过来的,通过升级成https来解决修改referer问题
-
location:告诉接下来要去哪个页面,搭配3XX使用
-
Set_Cookie:保存身份信息,下次访问此网络是就不需要在登录
http状态码(响应结果如何):
-
2开头:成功
-
3开头:重定向(302重定向到其他页面)
-
4开头:客户端异常(例404,418(彩蛋))
-
5开头:服务器异常(504(网关超时))
http请求(客户端发给服务器)
-
首行:方法+url+http版本号
-
Header:请求属性 冒号空格键值对
-
由空行结束
-
Body:空行后面的都是Body
http响应(服务器回发给客户端)
-
首行:http版本号 +状态码 +对状态码的含义补充
-
Header:键值对
-
空行表示Header结束
-
Body:空行后面都是Body
写一个最简易版本的http服务器
//不管什么请求,响应都是hello world
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
//其实可以使用C++多态来解决类似问题
typedef struct sockaddr sockaddr;//通用形式
typedef struct sockaddr_in sockaddr_in;//保存真正的IP地址和端口号
int ServerInit(const char *ip,short port)
{
int fd = socket(AF_INET,SOCK_STREAM,0);
if(fd < 0)
{
perror("socket!\n");
return -1;
}
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
socklen_t len = sizeof(addr);
int ret = bind(fd,(sockaddr *)&addr,len);
if(ret < 0)
{
perror("bind!\n");
return -1;
}
ret = listen(fd,5);
if(ret < 0)
{
perror("listen!\n");
return -1;
}
return fd;
}
void *ThreadEntry(void *arg)
{
int64_t new_fd = (int64_t)arg;
while(1)
{
char buf[1024 * 10] = {0};
read(new_fd,buf,sizeof(buf)-1);
printf("[request] %s\n",buf);
//构造http的响应
//首行
//字符串拼出来啥样页面就是啥样
const char* first_line = "HTTP/1.1 302 Found\n";
const char* blank_line = "\n";
//const char* body = "<html>sabi</html>";
char header[1024 *10] = {0};
//sprintf(header,"Content-Type:text/html;\nContent-Length:%lu\n",strlen(body));
sprintf(header,"Location:http://ww.baidu.com\n");//将会跳转到百度页面
write(new_fd,first_line,strlen(first_line));
write(new_fd,header,strlen(header));
write(new_fd,blank_line,strlen(blank_line));
//write(new_fd,body,strlen(body));
return NULL;
}
}
int main(int argc,char *argv[])
{
if(argc != 3)
{
printf("Usage ./http_server [ip] [port]\n");
return 1;
}
int listen_sork = ServerInit(argv[1],atoi(argv[2]));
if(listen_sork < 0)
{
printf("ServerInit error!\n");
return 1;
}
printf("ServerInit OK!\n");
//多线程版本
while(1)
{
sockaddr_in peer;
socklen_t len = sizeof(peer);
int64_t new_fd = accept(listen_sork,(sockaddr *)&peer,&len);
if(new_fd < 0)
{
perror("accept!\n");
continue;
}
pthread_t tid;
pthread_create(&tid,NULL,ThreadEntry,(void *)new_fd);
pthread_detach(tid);
}
return 0;
}
应用层协议:HTTP,HTTPS,FTP,SSH......,还有自定制的协议,序列化与反序列化
传输层(问题调试)
端口号
端口号范围划分
-
0-1023:知名端口号,一些知名的应用层协议http,ftp等都有固定的端口号
-
1024-65535:操作系统动态分配的端口号
知名的端口号
-
ssh:22
-
ftp:21
-
http:80
一个进程可以绑定多个端口号,创建多个进程就可以同时绑定多个端口号了
一个端口号不能被多个进程绑定
(易考)查看进程的PID
-
ps aux | grep 进程名:查看进程的PID
-
pidof 进程名
(易考)给一个端口号查看绑定的进程:
-
netstat -anp | grep 端口号
UDP协议
UDP协议端格式
教科书格式
通用格式