网络基础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在柱面上施加表面载荷问题(关于选取柱面一部分的问题)?

abaqus中幅值与载荷问题?

如果我在 C# 中发送 0 有效载荷数据,udp 数据包的大小是多少?

疲劳可靠性设计的基础是什么,知道吗?