restful框架,计算机网络

restful框架,计算机网络

个人对restful框架的理解:资源的表现层状态转化,简而言之,以资源(比如a进程的一个状态值,0或者1)为核心,一个资源对应一个URL,利用URL能获取或者操作对应的资源。

项目中,有a,b两个进程,基于restful框架,使用socket实现进程间通信的思路:
1. a,b两个进程分别启restServer,方法参考下文的服务端socket代码。
2. 注册URL:假设a要到b进程获取一个变量的值(资源),则b进程中需要注册相应的URL,比如为/rest/statusVal,将这个URL与资源(变量的值)绑定。方法是存到map<string, RestHandler*>中,键值string是URL,RestHandler是获取URL指定的资源的类。收到URL为/rest/statusVal的消息时,调用相应RestHandler类执行操作,获取数据。
3. 在a进程,使用curl实现客户端。指定URL,到b进程获取数据:curl -X GET http://127.0.0.1:8088/rest/statusVal
使用restful框架的优点是:URL和资源绑定,接口清晰,扩展性强。

TCP UDP

UDP:
在这里插入图片描述

TCP:
socket TCP

TCP如何保证可靠传输TCP可靠传输
确认应答(收到数据后回复ACK),
超时重传(发送数据后超时未收到ACK,重发数据),
序列号(连续),
检验和(发送方和接收方进行比对),
流量控制(TCP报文首部包含***窗口大小***,即接收端接收缓冲区剩余大小,接收端ACK报文中包含自己的窗口大小,发送方根据该窗口大小控制发送速度,若为0.则停止发送,并定期发送***窗口探测***包,等待接收端窗口大小更新),
拥塞控制(网络拥塞时,降低发送端的速率,减少丢包和超时重传)。

滑动窗口:滑动窗口

在这里插入图片描述

三次握手(防止客户端延迟的SYN被服务端收到又建立连接):
在这里插入图片描述
四次挥手(服务端先回复ACK,然后将剩下的数据发送,然后发送FIN):
在这里插入图片描述
TIME_WAIT阶段等2MSL:确保对端收到ACK包,若ACK丢失,对端会超时重发FIN,然后客户端收到后再发一次ACK。

  1. 访问量大的服务端可能存在大量的TIME_WAIT状态,解决:开启socket重用,允许将TIME_WAIT的socket重新用于TCP连接。
  2. linux内核中会维护两个队列:
      1)未完成队列:接收到一个SYN建立连接请求,处于SYN_RCVD状态,三次握手还未完成。
      2)已完成队列:已完成TCP三次握手过程,处于ESTABLISHED状态
      当有一个SYN到来请求建立连接时,就在未完成队列中新建一项。当三次握手过程完成后,就将套接口从未完成队列移动到已完成队列。
  3. accept发生在三次握手的哪一步
    accept会监听已完成队列是否非空,当队列为空时,accept就会阻塞。当队列非空时,就从已完成队列中取出一项并返回。而已完成队列中的都是三次握手过程已经完成的,因此accept发生在三次握手之后。
  4. TCP粘包,拆包
    因TCP面向字节流,如果发送的数据较大或较小时发生,如大于发送缓冲区剩余空间大小,就会发生粘包,UDP是面向报文的,不会粘包,拆包。
    粘包,拆包时,接收端很难区分两个包的界限,解决:
    a. 设置消息边界:服接收端按消息边界分离出消息内容。在包尾增加回车换行符进行分割,例如 FTP 协议。
    b. 消息头中包含表示消息总长度(或者消息体长度)的字段。
    在这里插入图片描述

TCP/IP协议族

第一层:应用层,主要有负责web浏览器的HTTP协议, 文件传输的FTP协议,负责电子邮件的SMTP协议,负责域名映射系统的DNS等。

第二层:传输层,可靠TCP,高效UDP。主要负责传输应用层的数据包。

第三层:网络层,IP协议。根据目的IP地址和路由表决定路由转发的路径,data->路由器1->路由器2->目标路由器。

第四层:数据链路层,ARP, RARP。IP地址<——>机器物理地址,通过物理地址找到对端主机。
在这里插入图片描述
在这里插入图片描述

简单的socket TCP CS通信代码
3. 服务端:

//g++ server.cpp -o server  -l pthread         使用静态库 libpthread.a
#include <iostream>
#include <string>
#include <string.h>

#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include<fcntl.h>
#include <pthread.h>
using namespace std;

static void* receiveMsg(void* connectId)
{
	pthread_detach(pthread_self());
	int readLen = 0;
	char recvData[1024] = {0,};
	while(true){
		readLen = read(*((int*)connectId), recvData, sizeof(recvData)-1);
		if(readLen > 0){
			cout<<"Receive: "<<recvData<<endl;
			memset(recvData, 0 ,sizeof(recvData));
		}
	}
}

int main()
{
	struct sockaddr_in sockaddr;
	sockaddr.sin_family = AF_INET; //sin_family表示地址类型,对于基于TCP/IP传输协议的通信,该值只能是AF_INET;
    sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY即0.0.0.0,泛指本机的意思,也就是表示本机的所有IP,监听本机所有IP的5030端口
    sockaddr.sin_port = htons(5030);  //端口号
	
	int listenId = socket(AF_INET, SOCK_STREAM, 0);  //创建基于tcp的socket
	if(listenId >= 0){
		cout<<"Create socket success."<<endl;
	}
	//int flags = fcntl(listenId, F_GETFL, 0);
	//fcntl(listenId,F_SETFL,flags|O_NONBLOCK);   //设置非阻塞,Windows下ioctlsocket()
	
	int bindRlt = bind(listenId, (struct sockaddr *)&sockaddr, sizeof(sockaddr));   //socket和IP端口号绑定
	int listenRlt = listen(listenId, 1024);
	if(bindRlt >= 0 && listenRlt >= 0){
		cout<<"Bind and listen success."<<endl;
	}
	else{
		cout<<"Bind and listen error."<<endl;
		close(listenId);
		return -1;
	}
	
	cout<<"Server Wait Client Connect......."<<endl;
	int connectId = accept(listenId, (struct sockaddr*) NULL, NULL);  //接收连接请求
	cout<<"Client Connect success."<<endl;
	
	pthread_t thread;
	pthread_create(&thread, NULL, receiveMsg, (void*)&connectId);  //收消息线程
	
	string sendData = "";
	while(true){
		cin>>sendData;
		if(sendData == "Q"){
			break;
		}
		int sendLen = send(connectId,sendData.c_str(),sendData.size()+1,0);
		if(sendLen == 0){
			cout<<"Cli disconnect."<<endl;
			break;
		}
	}
	close(connectId);
	cout<<"Server close."<<endl;
	connectId = -1;
	close(listenId);
	listenId = -1;
	return 0;
} 
  1. 客户端:
//g++ server.cpp -o server  -l pthread         使用静态库 libpthread.a

#include <iostream>
#include <string>
#include <string.h>

#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<fcntl.h>
#include <pthread.h>

using namespace std;

static void* receiveMsg(void* connectId)
{
	pthread_detach(pthread_self());
	int readLen = 0;
	char recvData[1024] = {0,};
	
	while(true){
		readLen = read(*((int*)connectId), recvData, sizeof(recvData)-1);
		if(readLen > 0){
			cout<<"Receive: "<<recvData<<endl;
			memset(recvData, 0 ,sizeof(recvData));
		}
	}
}

int main()
{
	struct sockaddr_in sockaddr;
	sockaddr.sin_family = AF_INET;
    sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    sockaddr.sin_port = htons(5030);
	
	int connectId = socket(AF_INET, SOCK_STREAM, 0);

	//int flags = fcntl(connectId, F_GETFL, 0);
	//fcntl(connectId,F_SETFL,flags|O_NONBLOCK);
	
	int res = connect(connectId, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
	if(res == 0){
		cout<<"Cli connect to server."<<endl;
	}

	string sendData = "";
	
	pthread_t thread;
	pthread_create(&thread, NULL, receiveMsg, (void*)&connectId);																																								
	while(true){	
		cin>>sendData;
		if(sendData == "Q"){
			break;
		}
		int sendLen = send(connectId,sendData.c_str(),sendData.size()+1,0);
		if(sendLen == 0){
			cout<<"Server disconnect."<<endl;
			break;
		}
	}
	
	close(connectId);
	cout<<"Cli close."<<endl;
	connectId = -1;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值