(计算机网络课程实验)以充电为背景定义一个简单的协议帧

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ccnuacmhdu/article/details/82947976

一、实验目的

定义一个自己的协议帧

二、实验内容

定义一个自己的协议帧,我将以充电控制协议为基础,建立一个自己的简单的帧,并以两台电脑为基础实现客户端服务端之间的通信。

三、实验过程

1.实验步骤:
在这里插入图片描述
2.帧格式及说明
帧格式如下表所示,发送帧的方式以字符串的形式发送,字符串固定长度为26个字符。本实验中,笔者只实现了客户端向服务器端发送帧的情况,完成了服务器端对帧的识别,差错校验等。鉴于本实验重在熟悉与理解协议的原理,而非关注于细节,所以笔者在进行帧识别的时候,仅仅检测客户端发过来的帧中是否包含帧头(charging),在差多校验上也没有使用复杂了CRC等校验算法,仅仅对大柜子编号、小柜子编号对应的字符串与校验部分的字符串进行简单匹配。
在这里插入图片描述

四、关键代码(为了便于阅读,笔者用伪代码说明算法思想)

在这里插入图片描述

五、实验结果

1、发送帧:charging1412121212charging(命令是1:请求充电)
客户端:
在这里插入图片描述
服务器端:
在这里插入图片描述
2、发送帧:charging2412121212charging(命令是2,查看电量)
客户端:
在这里插入图片描述

服务端:
在这里插入图片描述
3、发送帧:charging3412121212charging(命令是3,取走设备)
客户端:

服务器端:
在这里插入图片描述

六、总结

通过自定义协议帧格式,并动手编程,实现客户端与服务端之间传输,笔者对计算机网络中数据传输有了更加深刻的认识,了解到了底层网络中传输帧的原理,如何识别帧,如何进行校验,如何检测发送方的请求类型等等。至此,笔者想到计算机网络中定义了如此丰富多样的协议,不同的协议定义了不同的数据传输格式,这样一来,如此多的协议在计算机网络中运行,如此多的数据格式在计算机网络中运行,势必会使得计算机网络处理数据的复杂度变大,如何能够用较少的协议满足较多的需求是一个值得研究的课题!

七、实验改进(最终版实验代码2018.6.22)

经过反复多次实验后,对实验进行了一定改进,改进如下:

(1)改变执行程序的方式为命令行执行:

客户端(命令行执行):
在这里插入图片描述
服务器端:

在这里插入图片描述
(2)增加了加密解密机制(简单)

客户端加密:

for(unsigned int i=0;i<strlen(sendData);i++){
		sendData[i]+='a';
	}

服务端解密:

for(unsigned int i=0;i<strlen(revData);i++){
		revData[i]-='a';
	}

八、实验思考

在本实验中,笔者模仿充电协议,实现了一个简单的自定义帧,自己设计了一个简易的帧结构,实现了标记帧类型、帧传输的错误检测,传输过程中的加密等功能。通过这个实验的学习,我们可以很好的和教材中的内容结合在一起,这就是一个简单的协议或者说简单的帧,对协议的概念有了很深的认识,传输过程中进行了差错检测,这可以联系到教材中的CRC等错误检测方法,传输过程中进行了加密,这可以和DES,RSA等信息安全的知识联系起来,等等,通过实验有所获。

附上实验源代码:
client.cpp



//client



#include <WINSOCK2.H>
#include <STDIO.H>

#pragma  comment(lib,"ws2_32.lib")


int main(int argc, char* argv[])
{
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA data; 
    if(WSAStartup(sockVersion, &data) != 0)
    {
        return 0;
    }

    SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sclient == INVALID_SOCKET)
    {
        printf("invalid socket !");
        return 0;
    }

    sockaddr_in serAddr;
    serAddr.sin_family = AF_INET;
    serAddr.sin_port = htons(8888);
    serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 

	if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
    {
        printf("connect error !");
        closesocket(sclient);
        return 0;
    }

    //char sendData[300];

	//用户输入要向服务器请求的信息,为了简便,不再过多提示,只是实现通信功能即可




	printf("帧格式:charging1412121212charging\n\n");
	
	char *sendData=argv[1];
	//scanf("%s",sendData);
	
	//加密(简单加密一下)
	for(unsigned int i=0;i<strlen(sendData);i++){
		sendData[i]+='a';
	}
	
	
	send(sclient, sendData, strlen(sendData), 0);

	char recData[255];
	int ret = recv(sclient, recData, 255, 0);
	if(ret > 0)
	{
		recData[ret] = 0x00;
		printf(recData);
		printf("\n");
	}

	closesocket(sclient);
	WSACleanup();
    return 0;
}

server.cpp

//server

#include <stdio.h>
#include <winsock2.h>
#include<Windows.h>
#include<string.h>

#pragma comment(lib,"ws2_32.lib")

int main(int argc, char* argv[])
{
    //初始化WSA
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA wsaData;
    if(WSAStartup(sockVersion, &wsaData)!=0)
    {
        return 0;
    }

    //创建套接字
    SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(slisten == INVALID_SOCKET)
    {
        printf("socket error !");
        return 0;
    }

    //绑定IP和端口
    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(8888);
    sin.sin_addr.S_un.S_addr = INADDR_ANY; 
    if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        printf("bind error !");
    }

    //开始监听
    if(listen(slisten, 5) == SOCKET_ERROR)
    {
		
        printf("listen error !");
		
        return 0;
    }

    //循环接收数据
    SOCKET sClient;
    sockaddr_in remoteAddr;
    int nAddrlen = sizeof(remoteAddr);
    char revData[255]; 
    while (true)
    {
        printf("等待连接...\n");
        sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
        if(sClient == INVALID_SOCKET)
        {
            printf("accept error !");
            continue;
        }
        printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
        
        //接收数据
        int ret = recv(sClient, revData, 255, 0);        
		
		//简单加密的简单解密
		for(unsigned int i=0;i<strlen(revData);i++){
			revData[i]-='a';
		}
		
        if(ret > 0)
        {
			
            revData[ret] = 0x00;
			printf(revData);printf("\n");
			//用户请求进行ping
			//这里做一个粗糙的判断,如果客户端发过来的含有ping,就执行ping命令,要求客户端发送的
			//ping命令格式正确,并且服务端已经配置好了ping环境
			if(strstr(revData,"ping")){
				
				int len=strlen(revData);
				for(int i=len-1;i>=4;i--){
					revData[i+1]=revData[i];
				}
				revData[4]=' ';
				revData[len+1]=0x00;
			
				system(revData);
			}

			//用户请求进行充电
            if(strstr(revData,"charging")){
				//进行校验,检查是否有数据传输错误(粗糙检验)
				bool flag=true;
				for(int i=10;i<=13;i++){
					if(revData[i]!=revData[i+4]){
						flag=false;
						break;
					}
				}
				if(!flag){
					 char * sendData = "您的数据在传输过程中出错,请重新发送!\n";
					 send(sClient, sendData, strlen(sendData), 0);
					 printf("客户端数据出错!已经让客户端重发!\n");
				}
				else{
					if(revData[8]=='1'){
						char sendData[] = "欢迎来充电!您的设备存放位置是:大柜子编号是";
						int len=strlen(sendData);
						sendData[len]=revData[10];
						sendData[len+1]=revData[11];
						sendData[len+2]='\0';
						char tmp[]="小柜子编号是";
						int tmp_len=strlen(tmp);
						int len2=strlen(sendData);
						for(int i=0;i<tmp_len;i++){
							sendData[i+len2]=tmp[i];
						}
						sendData[len2+tmp_len]='\0';
						int len3=strlen(sendData);
						sendData[len3]=revData[12];
						sendData[len3+1]=revData[13];
						sendData[len3+2]='\0';
					

						send(sClient, sendData, strlen(sendData), 0);
						printf("有客户来充电,设备存放在大柜子%c%c,小柜子%c%c\n",revData[10],revData[11],revData[12],revData[13]);
					}
					else if(revData[8]=='2'){
						char sendData[] = "您手机的电量已经在显示屏上显示,请直接观看!";
						send(sClient, sendData, strlen(sendData), 0);
						printf("大柜子%c%c,小柜子%c%c设备的主人来查看电量了\n",revData[10],revData[11],revData[12],revData[13]);
					}
					else if(revData[8]=='3'){
						char sendData[] = "感谢使用,欢迎再次光临!";
						send(sClient, sendData, strlen(sendData), 0);
						printf("大柜子%c%c,小柜子%c%c设备的主人把设备取走了!\n",revData[10],revData[11],revData[12],revData[13]);
					}
				}
			}
        }

        //发送数据
       
        closesocket(sClient);
    }
    
    closesocket(slisten);
    WSACleanup();
    return 0;
}


猜你喜欢

转载自blog.csdn.net/ccnuacmhdu/article/details/82947976