计算机网络课程设计智能家居协议设计


一、项目描述

实现一个基于socket的物联网服务器(上位机),接收来自客户端的数据。实现一个物联网客户端,模拟设备。下位机连接各种设备,采集设备数据,发送至服务器,服务器根据协议对数据作出处理。
需要设置的设备有:
温度传感器:采集房间温度信息。
湿度传感器:采集房间湿度信息。
灯光:开关灯(多路),调节灯亮度(多路)
空调:可以根据服务器发来的指令进行调节模式(制冷、制热、送风)、设置温度、风速;还可以根据服务器的指令上传子自己的当前状态:模式、温度、风速。
门窗磁:可以根据服务器发来的指令打开或者关闭窗户。
插卡取电:插入卡表示有人进入,拔下卡表示房间无人,根据房间状态控制空调灯光

上位机根据下位机传来的数据更新设备状态并显示。
用户可以在上位机修改设备(空调、灯光)的状态,将命令下发给下位机,下位机收到后调整设备。
通信规则:
下位机10秒上传一次心跳,上位机收到后进行答复,答复数据中包含自己的时间;
下位机5秒上传设备信息(温度、湿度、灯光、空调、门窗、插卡取电),上位机收到后进行答复,答复数据中包含自己的时间。

二、协议的设计

功能长度解释
固定字3ABC
插卡取电10:无电 1:有电
调节空调10:关闭空调1:温度2:风速3:模式
调节灯光10:不调1:调节1号灯2:调节2号灯3:调节3号灯4:调节4号灯5:调节5号灯
温度值2显示温度
湿度2显示湿度
灯光亮度5一位显示一个灯
空调模式10:关闭状态1:制热2:制冷3:送风
风速1显示风速123
门窗10:关闭1:打开
目标温度2调节过后的温度
目标湿度2调节过后的湿度
日志61-2位:时,3-4位分,5-6位秒

三、项目实现

1.server.cpp(服务端)

先运行server.cpp.

#include<iostream>
#include<stdio.h>
#include <conio.h>
#include<Winsock2.h>
#include<fstream>
#include <ctime>
#include<cstdio>
#define N 10
using namespace std;
#include<windows.h>
#include <cstring>
#include <string>
#define N 10
#define random(a,b) (rand()%(b-a)+a)
#pragma comment(lib, "WS2_32")
#pragma comment(lib, "ws2_32.lib")
char recv_buf[100];
char send_buf[100];
char love[200];     //心跳数据报
void print(char *s)
{
    int key=s[3]-'0';
    int kongtiao1=s[15]-'0';
    int kongtiao2=s[16]-'0';
    int window=s[17]-'0';
    int num1=s[6]-'0';
    int num2=s[7]-'0';
    int tem=num1*10+num2;
    num1=s[8]-'0';
    num2=s[9]-'0';
    int shidu=num1*10+num2;
    int i;
    time_t tt = time(NULL);//这句返回的只是一个时间cuo
    tm* t= localtime(&tt);

    printf("当前的时间为%02d:%02d:%02d\n",

    t->tm_hour,
    t->tm_min,
    t->tm_sec);
    cout<<"------------------------------------"<<endl;

    if(key==0)
        cout<<"未插卡..."<<endl;
    else
        cout<<"读卡中..."<<endl;

    cout<<"收到来自温度传感器的数据: "<<tem<<"°  "<<endl;
    cout<<endl;
    cout<<"收到来自湿度传感器的数据: "<<shidu<<"%  "<<endl;
    if(kongtiao1==0)
        cout<<"空调模式:关"<<endl;
    else if(kongtiao1==1)
        cout<<"空调模式:制热"<<endl;
    else if(kongtiao1==2)
        cout<<"空调模式:制冷"<<endl;
    else if(kongtiao1==3)
        cout<<"空调模式:送风"<<endl;
    if(kongtiao2==0)
        cout<<"空调风速:关"<<endl;
    else if(kongtiao2==1)
        cout<<"空调风速:弱风"<<endl;
    else if(kongtiao2==2)
        cout<<"空调风速:中风"<<endl;
    else if(kongtiao2==3)
        cout<<"空调风速:强风"<<endl;
    for(i=10;i<15;i++)
    {
        if(s[i]=='0')
            cout<<"灯-"<<i-9<<":关"<<endl;
        else if(s[i]=='1')
            cout<<"灯-"<<i-9<<":柔和"<<endl;
        else if(s[i]=='2')
            cout<<"灯-"<<i-9<<":经典"<<endl;
        else if(s[i]=='3')
            cout<<"灯-"<<i-9<<":强光"<<endl;
    }
    if(window==0)
        cout<<"门窗模式:关"<<endl;
    else
        cout<<"门窗模式:开"<<endl;
    cout<<"\n------------------------------------"<<endl;
    cout<<endl;
    return ;
}


int main()
{
    WORD wsa = MAKEWORD(2,2);
    WSADATA wsaData;
    if(WSAStartup(wsa, &wsaData)!=0)
    {
        cout<<"初始化失败"<<endl;   //这进行初始化
        return 0;
    }
    //创建套接字
    SOCKET s_server = socket(AF_INET, SOCK_STREAM, 0);
    //AF_INET   面向网络的  IPV4
    //AF_INET6用于第6版因特网协议(IPv6)寻址
    //SOCK_STREAM   TCP链接   面向链接    SOCK_DGRAM 无连接 UDP
    if(s_server==INVALID_SOCKET) //INVALID_SOCKET是-1 错误标志
    {
        cout<<"socket创建失败"<<endl;
        return 0;
    }
    //这里配置server配置信息
    sockaddr_in server_addr;    //创建sockaddr_in结构体
    server_addr.sin_family = AF_INET;   //IPV4协议
    server_addr.sin_port = htons(8888);     //本地端口8888
    server_addr.sin_addr.S_un.S_addr = INADDR_ANY;   //设置地址 监听本地端口
    //利用bind函数将socket和配置信息绑定
    //bind通常和下面的listen配套使用 处于被动链接中泰
    if   (  bind( s_server,(SOCKADDR *)&server_addr,sizeof(SOCKADDR)) ==SOCKET_ERROR )
    {
        //socket和配置绑定
        cout<<"ERROR bind!!"<<endl;  //绑定错误
        WSACleanup();
    }

    if(listen( s_server,5 )<0)
    {
        cout<<"监听失败"<<endl;
    }
    cout<<"监听链接请求~~~"<<endl;
    sockaddr_in clinet_addr;   //用于获取客户端地址端口信息 用于回传
    SOCKET s_accept;
    //这里定义了一个用于接收的sockaddr_in名字为s_accept。用于接收客户端的地址信息和端口信息,用于回传。
    int len=sizeof(SOCKADDR);
    s_accept = accept(s_server,(SOCKADDR *)&clinet_addr,&len);
    //在这里阻塞 挂起等待

    if( s_accept ==SOCKET_ERROR  )  //
    {
        cout<<"connect error"<<endl;
        return 0;
    }
    cout<<"connection is OK;ready to accept"<<endl;
    int count1=0;
    while(1)
    {
        int recv_len= recv(s_accept,recv_buf,100,0);
        //这里 即使链接断开 也能继续监听 服务端不关闭
        if(recv_len<0)
        {
            cout<<"服务器继续监听~~~~"<<endl;
            s_accept = accept(s_server,(SOCKADDR *)&clinet_addr,&len);
            //客户端断开阻塞,挂起等待。在这里阻塞 挂起等待
            continue;
            if( s_accept ==SOCKET_ERROR  )  //
            {
                cout<<"connect error"<<endl;
                return 0;
            }
        }
        char recv_message[100];     //接收到的数据帧
        strcpy(recv_message,recv_buf);
        int message_len = strlen(recv_message);   //接收到的数据帧的长度
        count1++;
        if(count1%2==0)
        {
            cout<<"心跳:"<<endl;
            recv(s_accept,love,100,0);
            cout<<love<<endl<<endl;
        }
        print(recv_message);

        int key;
        int control_k;
        int control_d;
        int wendu;
        int shidu;
        int deng[N];
        int kongtiao1;
        int kongtiao2;
        int window;
        string str0="ABC";
        key=1;
        control_k=4;
        control_d=0;
        int num1=recv_message[6]-'0';
        int num2=recv_message[7]-'0';
        wendu=num1*10+num2;
        num1=recv_message[8]-'0';
        num2=recv_message[9]-'0';
        shidu=num1*10+num2;
        int i;
        for(i=10;i<15;i++)
            deng[i-10]=recv_message[i]-'0';
        kongtiao1=recv_message[15]-'0';
        kongtiao2=recv_message[16]-'0';
        if(wendu>=18)
            window=1;
        else
            window=0;

        int dwendu=wendu;
        int dshidu=shidu;
        if(key==1)
        {
            if(wendu<18)
            {
                dwendu=18;
                kongtiao1=1;
            }
            else if(wendu>25)
            {
                dwendu=25;
                kongtiao1=2;
            }
            else
            {
                dwendu=wendu;
                kongtiao1=3;
            }
            if(shidu<40)
            {
                dshidu=40;
                kongtiao2=3;
            }
            else if(shidu>50)
            {
                dshidu=50;
                kongtiao2=2;
            }
            else
            {
                dshidu=shidu;
                kongtiao2=1;
            }
        }

        string str1=to_string(key);
        string str2=to_string(control_k);
        string str3=to_string(control_d);
        string str4=to_string(wendu);
        string str5=to_string(shidu);

        string str7=to_string(kongtiao1);
        string str8=to_string(kongtiao2);
        string str9=to_string(window);
        string str10=to_string(dwendu);
        string str11=to_string(dshidu);
        cout<<"可以进行人工控制!!!"<<endl;
        cout<<"空调1温度/2模式/3风速  灯光(1-5)"<<endl;
        string s,t;
        Sleep(3*1000);
        if(kbhit())
        {
            cin>>s;
            if(s[0]=='1')
            {
                cout<<"设置温度:"<<endl;
                cin>>t;
                str10=t;

            }
            else if(s[0]=='2')
            {
                cout<<"设置模式:"<<endl;
                cin>>t;
                str7=t;
            }
            else if(s[0]=='3')
            {
                cout<<"设置风速:"<<endl;
                cin>>t;
                str8=t;
            }
            cout<<"设置亮度:"<<endl;
            cin>>t;
            int m=s[1]-'0';
            deng[m]=t[0]-'0';
        }
        string str6=to_string(deng[0]);
        for(i=1;i<5;i++)
                str6+=to_string(deng[i]);
        time_t tt = time(NULL);//这句返回的只是一个时间cuo
        tm* a= localtime(&tt);

        string strt1=to_string(a->tm_hour);
        if(a->tm_hour<10)
            strt1='0'+strt1;
        string strt2=to_string(a->tm_min);
        if(a->tm_min<10)
            strt2='0'+strt2;
        string strt3=to_string(a->tm_sec);
        if(a->tm_sec<10)
            strt3='0'+strt3;
        string str=str0+str1+str2+str3+str4+str5+str6+str7+str8+str9;
        str=str+str10+str11;
        str=str+strt1+strt2+strt3;
        int j=0;
        memset(send_buf,0,sizeof(send_buf));
        for(int i=0; i<str.length(); i++)
        {
            send_buf[j]=str[i];
            j++;
        }

        cout<<send_buf<<endl;


        send(s_accept,send_buf,100,0);

        cout<<"发送成功"<<endl<<endl;

    }
    closesocket(s_server);
    closesocket(s_accept);
    //释放DLL资源
    WSACleanup();
    return 0;
}




2.client.cpp(客服端)

#include<iostream>
#include<stdio.h>
#include<Winsock2.h>
#include<windows.h>
#include <ctime>
#include <cstring>
#include <string>
#define N 10
#define random(a,b) (rand()%(b-a)+a)
#pragma comment(lib, "WS2_32")
using namespace std;


char send_buf[200];     //发送数据报
char accept_buf[200];   //接受数据报
char love[200];     //心跳数据报
void tcpxy();           //生成上传服务器报文
void analysis(char receive[]);  //对服务器传回的报文进行解析
void get(int n);
int main()
{
    WORD wsa = MAKEWORD(2,2);
    WSADATA wsaData;
    //WSADATA结构体中主要包含了系统所支持的Winsock版本信息  WSA API
    if(WSAStartup(wsa, &wsaData)!=0)
    {
        cout<<"初始化失败"<<endl;   //这进行初始化
        return 0;
    }
    SOCKET s_server = socket(AF_INET, SOCK_STREAM, 0);
    if(s_server==INVALID_SOCKET)
    {
        cout<<"socket创建失败"<<endl;
        return 0;
    }
    sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;       //IPV4协议
    server_addr.sin_port = htons(8888);     //服务器端口
    server_addr.sin_addr.S_un.S_addr = inet_addr("192.168.56.1");  //服务器IP,改成自己电脑的IP
    if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR)  //链接失败
    {
        cout << "server connnet fail!" << endl;
        WSACleanup();
        return 0;
    }
    else
    {
        cout << "server connnet succeed!" << endl<<endl;
    }
    Sleep(1*1000);
    cout<<"开始上传温度和湿度传感器信息..."<<endl<<endl;
    int count1=0,count2=2;
    while(1)
    {
        count1++;
        cout<<"上传服务器报文为:"<<endl;
        tcpxy();
        Sleep(2*1000);//延时3秒
        int res_len = send(s_server,send_buf,100,0);

        if(res_len<0)
        {
            cout<<"error"<<endl;
            return 0;
        }
        if(count1%2==0)
        {
            get(count2%2);
            send(s_server,love,100,0);
            count2++;
        }
        cout<<"报文发送成功,等待接受"<<endl<<endl;
        recv(s_server, accept_buf, 200, 0);
        cout<<"收到服务器端消息";
        analysis(accept_buf);
        cout<<"------------------------------------------------"<<endl<<endl<<endl;

    }

    closesocket(s_server);
    //释放DLL资源
    WSACleanup();
    return 0;
}

void get(int n)
{
    memset(love,0,sizeof(love));
    string a=to_string(n);
    for(int i=0; i<20; i++)
        love[i]=a[0];
}
void analysis(char *s)  //解析
{
    cout<<"传输的报文为:"<<s<<endl;
    cout<<"报文解析结果为:"<<endl;
    int key=s[3]-'0';
    int kongtiao1=s[15]-'0';
    int kongtiao2=s[16]-'0';
    int window=s[17]-'0';
    int num1=s[6]-'0';
    int num2=s[7]-'0';
    int tem=num1*10+num2;
    num1=s[8]-'0';
    num2=s[9]-'0';
    int shidu=num1*10+num2;
    num1=s[18]-'0';
    num2=s[19]-'0';
    int dwendu=num1*10+num2;
    num1=s[20]-'0';
    num2=s[21]-'0';
    int dshidu=num1*10+num2;
    num1=s[22]-'0';
    num2=s[23]-'0';
    int hour=num1*10+num2;
    num1=s[24]-'0';
    num2=s[25]-'0';
    int min1=num1*10+num2;
    num1=s[26]-'0';
    num2=s[27]-'0';
    int sec=num1*10+num2;
    int i;
    cout<<"------------------------------------"<<endl;

    printf("服务端时间为%02d:%02d:%02d\n",hour,min1,sec);
    if(key==0)
        cout<<"未插卡..."<<endl;
    else
        cout<<"读卡中..."<<endl;

    cout<<"当前温度传感器的数据: "<<tem<<"°  "<<endl;
    cout<<"当前湿度传感器的数据: "<<shidu<<"%  "<<endl;
    cout<<endl;
    cout<<"目标温度设置为: "<<dwendu<<"°  "<<endl;
    cout<<"目标湿度设置为: "<<dshidu<<"%  "<<endl;
    cout<<"设置";
    if(kongtiao1==0)
        cout<<"空调模式:关"<<endl;
    else if(kongtiao1==1)
        cout<<"空调模式:制热"<<endl;
    else if(kongtiao1==2)
        cout<<"空调模式:制冷"<<endl;
    else if(kongtiao1==3)
        cout<<"空调模式:送风"<<endl;
    cout<<"设置";
    if(kongtiao2==0)
        cout<<"空调风速:关"<<endl;
    else if(kongtiao2==1)
        cout<<"空调风速:弱风"<<endl;
    else if(kongtiao2==2)
        cout<<"空调风速:中风"<<endl;
    else if(kongtiao2==3)
        cout<<"空调风速:强风"<<endl;
    for(i=10;i<15;i++)
    {
        if(s[i]=='0')
            cout<<"灯-"<<i-9<<":关"<<endl;
        else if(s[i]=='1')
            cout<<"灯-"<<i-9<<":柔和"<<endl;
        else if(s[i]=='2')
            cout<<"灯-"<<i-9<<":经典"<<endl;
        else if(s[i]=='3')
            cout<<"灯-"<<i-9<<":强光"<<endl;
    }
    cout<<"设置";
    if(window==0)
        cout<<"门窗模式:关"<<endl;
    else
        cout<<"门窗模式:开"<<endl;
    cout<<"\n------------------------------------"<<endl;
    cout<<endl;
    return ;
}


void tcpxy()
{
    memset(send_buf,0,sizeof(send_buf));
    int j=0,i;
    srand((int)time(0));  // 产生随机种子  把0换成NULL也行
    int key;
    int control_k;
    int control_d;
    int wendu;
    int shidu;
    int deng[N];
    int kongtiao1;
    int kongtiao2;
    int window;
    string str0="ABC";
    key=1;
    if(key==0)
    {
        control_k=0;
        control_d=0;
        wendu=random(10,40);
        shidu=random(15,80);
        for(i=0;i<5;i++)
            deng[i]=0;
        kongtiao1=0;
        kongtiao2=0;
        window=0;
    }
    else
    {
        control_k=0;
        control_d=0;
        wendu=random(10,40);
        shidu=random(15,80);
        for(i=0;i<5;i++)
            deng[i]=random(0,3);
        kongtiao1=random(0,3);
        kongtiao2=random(0,3);
        window=random(0,1);
    }
    string str1=to_string(key);
    string str2=to_string(control_k);
    string str3=to_string(control_d);
    string str4=to_string(wendu);
    string str5=to_string(shidu);
    string str6=to_string(deng[0]);
    for(i=1;i<5;i++)
            str6+=to_string(deng[i]);
    string str7=to_string(kongtiao1);
    string str8=to_string(kongtiao2);
    string str9=to_string(window);

    string str=str0+str1+str2+str3+str4+str5+str6+str7+str8+str9; //帧格式(协议)

    for(int i=0; i<str.length(); i++)
    {
        send_buf[j]=str[i];
        j++;
    }
    cout<<send_buf<<endl;
}

四、实验结果显示

在这里插入图片描述
在这里插入图片描述


总结

本次实验在Windows环境下,网络应用程序编程接口称作Windows Socket。使用bind函数绑定端口号和IP地址,connect函数实现套接字连接到目的地址,实现服务端和客户端之间的连接。Listen函数在服务端申请到套接字和调用bind与本地地址绑定后,使用listen函数等待客户机程序的链接。Accept函数接受连接函数,send、recv函数实现发送和接受数据。使用完scoket之后要closesocket关闭套接字。通过socket通信,传输设计的通信帧实现通信同步。

  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值