网络基础2
Posted DR5200
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络基础2相关的知识,希望对你有一定的参考价值。
文章目录
将数据多变一的过程(方便网络发送和接受),称为序列化,将数据一变多的过程,称为反序列化(方便上层应用程序正常使用数据),如何序列化和反序列化是由协议规定的,而协议是根据应用场景所决定的
网络版本的计算器代码理解协议
// protocol.hpp 自定义协议
#pragma once
typedef struct request
int x;
int y;
int op;
request_t;
typedef struct response
int code; // 0->success
int result;
response_t;
// server.cc
#include<iostream>
#include<string>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<pthread.h>
#include"protocol.hpp"
#define BACKLOG 5
void* Routine(void* arg)
pthread_detach(pthread_self());
int sock = *(int*)arg;
while(1)
request_t rq;
ssize_t size = recv(sock,&rq,sizeof rq,0);
if(size > 0)
else if(s == 0)
else
close(sock);
delete (int*)arg;
return nullptr;
// ./server port
int main(int argc,char* argv[])
if(argc != 2)
std::cout<<"Usage : "<<argv[0]<<" port "<<std::endl;
exit(1);
int listen_sock = socket(AF_INET,SOCK_STREAM,0);
if(listen_sock < 0)
exit(2);
struct sockaddr_in local;
memset(&local,0,sizeof local);
local.sin_family = AF_INET;
local.sin_port = htons(atoi(argv[1]));
local.sin_addr.s_addr = INADDR_ANY;
if(bind(listen_sock,(struct sockaddr*)&local,sizeof local) < 0)
exit(3);
if(listen(listen_sock,BACKLOG) < 0)
exit(4);
while(1)
struct sockaddr_in peer;
memset(&peer,0,sizeof peer);
socklen_t len = sizeof peer;
int sock = accept(listen_sock,(struct sockaddr*)&peer,&len);
if(sock < 0)
continue;
pthread_t tid;
int* p = new int(sock);
pthread_create(&tid,nullptr,Routine,p);
// client.cc
#include<iostream>
#include<string>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
// ./client server_ip server_port
int main(int argc,char* argv[])
if(argc != 3)
std::cout<<"Usage : "<<argv[0]<<" server_ip server_port "<<std::endl;
exit(1);
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0)
exit(2);
struct sockaddr_in peer;
memset(&peer,0,sizeof peer);
peer.sin_family = AF_INET;
peer.sin_addr.s_addr = inet_addr(argv[1]);
peer.sin_port = htons(atoi(argv[2]));
if(connect(sock,(struct sockaddr*)&peer,sizeof peer) < 0)
exit(3);
while(1)
request_t rq;
std::cout<<"输入第一个数据 : ";
cin>>rq.x;
std::cout<<"输入第二个数据 : ";
cin>>rq.y;
std::cout<<"输入操作符 : ";
cin>>rq.op;
send(sock,&rq,sizeof rq,0);
response_t rsp;
recv(sock,&rsp,sizeof rsp,0);
std::cout<<"status : "<<rsp.code<<std::endl;
std::cout<<rq.x<<rq.op<<rq.y<<"="<<rsp.result<<std::endl;
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
flags : 设置发送方式,设置为0为阻塞式发送
返回值为实际发送的字节数
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
flags : 设置发送方式,设置为0为阻塞式接受
返回值为实际读取的字节数
HTTP协议
说明 :
(1). 标识机器我们用的是公网IP,而IP不适合给人看,所以使用域名的方式
(2). 服务和端口的对应关系是明确的(http协议对应的端口号就是80)
(3). http协议本质是要获得某种资源(视频,音频,网页,图片)
(4). 登录信息和端口号可以省略
(5). 上网的大部分行为,都存在着进程间通信,大部分的上网行为,无非2种,把本地的数据推送到服务器(搜索/注册/登录/下单),把服务器上的资源数据拿到本地(短视频/网络小说)
urlencode和urldecode
像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现.
比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.
转义的规则如下:
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY
http是基于请求与响应的应用层服务,常规情况下,http(https)底层使用的传输层协议是 tcp
#include<iostream>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<cstring>
#include<unistd.h>
#include<sys/wait.h>
#define BACKLOG 5
int main()
int listen_sock = socket(AF_INET,SOCK_STREAM,0);
if(listen_sock < 0)
perror("listen_sock\\n");
return 1;
struct sockaddr_in local;
memset(&local,0,sizeof local);
local.sin_family = AF_INET;
local.sin_port = htons(8081);
local.sin_addr.s_addr = INADDR_ANY;
if(bind(listen_sock,(struct sockaddr*)&local,sizeof local) < 0)
perror("band\\n");
return 2;
if(listen(listen_sock,BACKLOG) < 0)
perror("listen\\n");
return 3;
while(1)
struct sockaddr_in peer;
memset(&peer,0,sizeof peer);
socklen_t len = sizeof peer;
int sock = accept(listen_sock,(struct sockaddr*)&peer,&len);
if(sock < 0)
std::cout<<"accept error"<<std::endl;
continue;
if(fork() == 0)
close(listen_sock);
if(fork() > 0) exit(0);
// read http request
char buffer[1024];
recv(sock,buffer,sizeof buffer,0);
std::cout<<"################### http request begin ##########################"<<std::endl;
std::cout<<buffer<<std::endl;
std::cout<<"################### http request end ##########################"<<std::endl;
exit(0);
close(sock);
waitpid(-1,nullptr,0);
写完上述简单的tcp服务器,我们可以在浏览器中输入IP地址和端口号,服务器就会收到http请求
或使用 post man 给服务器发送http请求
使用 post man 发送http请求(GET方法)
在浏览器中输入 IP地址 + 端口号 + /a/b/c/d.html(资源路径),服务器收到如下请求
或使用 post man 给服务器发送http请求
使用 post man 发送http请求(GET方法)
http请求格式 :
请求行 : 请求方法 url http协议版本(客户端版本)
请求报头 : key: value
key: value
…
(请求的相关属性,如是否需要长链接,浏览器的相关信息等等)
空行
请求正文(非必须)
说明 :
(1). 请求行,请求报头,空行全部是按行方式陈列的
(2). 请求正文一般是用户的相关信息或者数据,当我们登录注册时,会把我们的用户名,密码信息放到正文
(3). 服务器端在收到 http 请求后,可以按行进行循环读取,一直读到空行,就证明已经把请求报头读完了,所以 http 请求空行的含义是将报头和有效载荷进行分离的特殊符号
请求方法 : 常见 GET POST
GET : 获取资源,也有可能上传数据(百度搜索时可以看到搜索关键字)
POST : 上传数据,参数不会被同步到 url 当中,而是通过正文发送
url : 想访问的资源路径
http响应格式 :
状态行 : http协议(服务器端版本) 状态码 状态码描述
响应报头 : key: value
key: value
…
空行
响应正文(html/图片/音频等资源)(非必须)
客户端在收到 http 响应后,可以按行进行循环读取,一直读到空行,就证明已经把响应报头读完了
为什么要提供客户端和服务器端的http协议版本?
为了解决兼容性的问题, 客户端可能使用老的版本,服务器可能使用新的版本,服务器根据客户端的版本提供对应的服务
状态码 : 请求的结果(服务器把请求的事情做的怎么样)
telnet www.baidu.com 80
可以得到百度服务器的响应
GET 方法 :
(1). 直接获取对应的资源信息,比如网页!
(2). GET可以带参数(参数在 url 后面),在 url 将信息传递给服务器
https://cn.bing.com/search?
// 参数
q=%E6%80%AA%E5%BD%A2&cvid=8ace6f76d2c14d5ba5f36899f1c292de&aqs=edge.7.69i59i450l8.54419j0j1&FORM=ANNTA1&PC=U531
POST 方法 :
将数据提交给服务器,通过正文提交(不通过 url 传参)
GET和POST如果传参,GET通过url,POST通过正文,因此 POST 比 GET 能够传递更多的数据/更私密
http的特点 :
(1). 无状态的(第一次请求/第二次请求/…没有关系)
http 状态码
3XX重定向
301永久移动(301 Moved Permanently)
302临时移动(307 Moved Temporarily)
307临时移动(307 Moved Temporarily)
#include<iostream>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<cstring>
#include<unistd.h>
#include<sys/wait.h>
#define BACKLOG 5
int main()
int listen_sock = socket(AF_INET,SOCK_STREAM,0);
if(listen_sock < 0)
perror("listen_sock\\n");
return 1;
struct sockaddr_in local;
memset(&local,0,sizeof local);
local.sin_family = AF_INET;
local.sin_port = htons(8080);
local.sin_addr.s_addr = INADDR_ANY;
if(bind(listen_sock,(struct sockaddr*)&local,sizeof local) < 0)
perror("band\\n");
return 2;
if(listen(listen_sock,BACKLOG) < 0)
perror("listen\\n");
return 3;
while(1)
struct sockaddr_in peer;
memset(&peer,0,sizeof peer);
socklen_t len = sizeof peer;
int sock = accept(listen_sock,(struct sockaddr*)&peer,&len);
if(sock < 0)
std::cout<<"accept error"<<std::endl;
continue;
if(fork() == 0)
close(listen_sock);
if(fork() > 0) exit(0);
// read http request
char buffer[1024];
recv(sock,buffer,sizeof buffer,0);
std::cout<<"################### http request begin ##########################"<<std::endl;
std::cout<<buffer<<std::endl;
std::cout<<"################### http request end ##########################"<<std::endl;
std::string status_line = "http/1.1 307 Temporary Redirect\\n";
std::string response_header = "Content-Length: 40\\n";
response_header += "location: https://www.qq.com/\\n";
std::string blank = "\\n";
send(sock,status_line.c_str(),status_line.size(),0);
send(sock,response_header.c_str(),response_header.size(),0);
send(sock,blank.c_str(),blank.size(),0);
exit(0);
close(sock);
waitpid(-1,nullptr,0);
上述代码在浏览器中输入IP地址加端口号就可以跳转到腾讯的官网
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能
(当我们登录一个网站时,会输入账号和密码,短时间内再次登录,就不需要再输入账号和密码)
当第一次输入账号和密码时,账号和密码会在服务器端进行认证,服务器认证成功后,会把 Set-Cookie: 用户数据 响应回浏览器,浏览器识别到用户数据后会保存到浏览器的Cookie文件中,第二次发送登录请求时会发送 Cookie: 用户数据 字段给服务器,从而不用再次输入账号和密码,但 Cookie 文件容易被别人窃取,因此并不安全
当第一次输入账号和密码时,账号和密码会在服务器端进行认证,服务器认证成功后,会生成一个唯一的 session_id ,把 Set-Cookie: session_id 响应回浏览器,浏览器识别后会保存到浏览器的Cookie文件中,第二次发送登录请求时会发送 Cookie: session_id 字段给服务器,服务器确认后从而不用再次输入账号和密码
https加密流程:
http/1.0 是基于 request 和 response 方式的(一次请求,一次响应,然后断开链接),但这样太浪费资源,所以 http/1.1 支持长链接,客户端可以向服务器同时发送多个请求
传输层
http等上层协议,本质其实不是把请求和响应发送给网络,而是把自己的数据给了下层协议(TCP)
(1). 一个进程是否可以bind多个端口号?
可以
(2). 一个端口号是否可以被多个进程bind?
不可以,一个端口号只能唯一标识一个进程
iostat
用于输出磁盘IO 和 CPU的统计信息
-c: 显示CPU使用情况
-d: 显示磁盘使用情况
-N: 显示磁盘阵列(LVM) 信息
-n: 显示NFS 使用情况
-k: 以 KB 为单位显示
-m: 以 M 为单位显示
-t: 报告每秒向终端读取和写入的字符数和CPU的信息
-V: 显示版本信息
-x: 显示详细信息
-p:[磁盘] 显示磁盘和分区的情况
pidof[进程名]
功能: 通过进程名查看进程id
UDP协议(用户数据报协议)
UDP协议本质上是内核中的一种数据结构,可以定制UDP报头并添加UDP数据
UDP协议简介:
(1). 16位源端口号,16号目的端口号
在 socket 编程中,使用 sendto 系统调用时会填充 struct sockaddr_in 结构体,将填充的结构体中的端口号信息交给udp协议
(2). 16位UDP长度
整个UDP报文的长度
(3). 16位UDP检验和
发送前检验和 和 发送到对方后检验和一样说明数据在网络传输中没有发生过错误
说明 :
(1). UDP如何保证报头和有效载荷分离?
UDP协议采用定长报头
(2). UDP如何决定自己
以上是关于网络基础2的主要内容,如果未能解决你的问题,请参考以下文章
2018-2019-2 20165332《网络攻防技术》Exp5 MSF基础应用
《Entity Framework 6 Recipes》翻译系列 -----第二章 实体数据建模基础之有载荷和无载荷的多对多关系建模 (转)
abaqus在柱面上施加表面载荷问题(关于选取柱面一部分的问题)?