题目描述:
实现一个基于socket的物联网服务器,接收来自客户端的数据。实现一个物联网客户端,模拟设备。客户端产生数据,发送至服务器,服务器根据协议对数据作出处理。
需要模式的设备有:
温度传感器:采集房间温度信息。
湿度传感器:采集房间湿度信息。
空调:可以根据服务器发来的指令进行调节模式(制冷、制热、送风)、设置温度、风速;还可以根据服务器的指令上传子自己的当前状态:模式、温度、风速。
门窗磁:可以根据服务器发来的指令打开或者关闭窗户。
要求:
设计通信协议完成数据的双向传输,应用层协议应包含首部和数据部分。
学校:烟台大学计算机与控制工程学院2017级
完成时间:2019.12
老师:赵老师
具体实现过程参考附带的链接资源,此处只提供源码和一些实验指导,因为已经是放寒假已经半个月了,所以博客写的有些时间久远,大部分思路是在链接资源的实验报告里面:
CSDN资源:https://download.csdn.net/my
百度云:链接:https://pan.baidu.com/s/1DBFi4i2g1lL3MoQC6MQAGA
提取码:54hx
压缩包里面还有个一复杂版本的,那是我原来从GitHub上找的demo,比较完整,而且实现一些死锁问题的解决方案。
本次实验时间还是比较长的。但是实验还是比较匆忙的完成,因为大家都是提前验收的,没有考虑一些像是死锁一样的问题。
server.cpp
#include
#include
#include
#include
#include
using namespace std;
#pragma comment(lib, "ws2_32.lib")
char recv_buf[100];
char send_buf[100];
void print(char *s)
{
int t, p;
if(s[3] == '0'){ //温度传感器
p = 0;
t = 6;
int tem; // 温度
int start_num = s[4] - '0';
int num = s[5] - '0';
cout<<"------------------------------------"<
tem = 0;
tem += (s[t++] - '0')*10;
tem += (s[t++] - '0');
cout<
}
cout<<"\n------------------------------------"<
else if(s[3] == '1'){ //湿度传感器
p = 0;
t = 6;
int shidu; // 湿度
int start_num = s[4] - '0';
int num = s[5] - '0';
cout<<"收到来自"<
shidu = 0;
shidu += (s[t++] - '0')*10;
shidu += (s[t++] - '0');
cout<
}
}
cout<
}
int main()
{
WORD wsa = MAKEWORD(2,2);
WSADATA wsaData;
if(WSAStartup(wsa, &wsaData)!=0)
{
cout<<"初始化失败"<
}
//创建套接字
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创建失败"<
}
//这里配置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!!"<
}
if(listen( s_server,5 )<0)
{
cout<<"监听失败"<
cout<<"监听链接请求~~~"<
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"<
}
cout<<"connection is OK;ready to accept"<
while(1)
{
int recv_len= recv(s_accept,recv_buf,100,0);
//这里 即使链接断开 也能继续监听 服务端不关闭
if(recv_len<0)
{
cout<<"服务器继续监听~~~~"<
//客户端断开阻塞,挂起等待。在这里阻塞 挂起等待
continue;
if( s_accept ==SOCKET_ERROR ) //
{
cout<<"connect error"<
}
}
char recv_message[100]; //接收到的数据帧
strcpy(recv_message,recv_buf);
int message_len = strlen(recv_message); //接收到的数据帧的长度
print(recv_message); //输出温度/湿度の状态
char solid_head[] = {"5A"}; //固定头 帧头 } /* 5A00311723, 10 client.cpp #include int main() WORD wsa = MAKEWORD(2,2); while(1) //cout< closesocket(s_server); void analysis(char receive[]) //解析 memset(send_buf,0,sizeof(send_buf)); for(int i=0; i 最重要的是感谢周学长和虎 学长o(╥﹏╥)o,原来找的那个demo太大太难了,入手慢,感谢o(╥﹏╥)o
char function_num[] = {"0"}; //S-->C
char device_type[3]; //设备类型,0-空调,1-门窗磁
//判断空调
if(recv_message[3] == '0' || recv_message[3] == '1')
device_type[0] = '0'; // 0代表空调
device_type[1] = '\0';
char device_start[] = {"F"}; //不用 不使用
char device_num[] = {"F"}; //不用
strcat(send_buf,solid_head);
strcat(send_buf,function_num);
strcat(send_buf,device_type);
strcat(send_buf,device_start);
strcat(send_buf,device_num);
int p;
if(recv_message[3] == '0'){ //发来的是温度
cout<<"调节空调温度,发送数据帧:";
p = 6;
int temsensor_num = recv_message[5] - '0';
int temperature = 0;
while(temsensor_num--){
temperature += (recv_message[p++] - '0')*10;
temperature += (recv_message[p++] - '0');
}
temperature /= (recv_message[5] - '0'); //空调模式
if(temperature<18){
char moshi[] = {"1"}; //制热
char tem_standard[] = {"18"};
char wind_speed[] = {"1"};
strcat(send_buf,moshi);
strcat(send_buf,tem_standard);
strcat(send_buf,wind_speed);
}
else if(temperature>18){
char moshi[] = {"0"}; //制冷
char tem_standard[] = {"18"};
char wind_speed[] = {"1"};
strcat(send_buf,moshi);
strcat(send_buf,tem_standard);
strcat(send_buf,wind_speed);
}
else{
char moshi[] = {"2"}; //送风
char tem_standard[] = {"18"};
char wind_speed[] = {"0"};
strcat(send_buf,moshi);
strcat(send_buf,tem_standard);
strcat(send_buf,wind_speed);
}
}
if(recv_message[3] == '1'){ //发来的是湿度
cout<<"调节空调湿度,发送数据帧:";
p = 6;
int humsensor_num = recv_message[5] - '0';
int humperature = 0;
while(humsensor_num--){
humperature += (recv_message[p++] - '0')*10;
humperature += (recv_message[p++] - '0');
}
humperature /= (recv_message[5] - '0');
if(humperature<30){
char moshi[] = {"3"}; //提高湿度
char tem_standard[] = {"30"};
char wind_speed[] = {"1"};
strcat(send_buf,moshi);
strcat(send_buf,tem_standard);
strcat(send_buf,wind_speed);
}
else if(humperature>30){
char moshi[] = {"4"}; //降低湿度
char tem_standard[] = {"30"};
char wind_speed[] = {"1"};
strcat(send_buf,moshi);
strcat(send_buf,tem_standard);
strcat(send_buf,wind_speed);
}
else{
char moshi[] = {"2"}; //送风
char tem_standard[] = {"30"};
char wind_speed[] = {"0"};
strcat(send_buf,moshi);
strcat(send_buf,tem_standard);
strcat(send_buf,wind_speed);
}
}
//判断门窗锁
//cout<
send_buf[3] = '1'; //此时设备为门窗磁
if(recv_message[3] == '0' || recv_message[3] == '1'){
cout<<"调节门窗,发送数据帧:";
p = 6;
int temsensor_num = recv_message[5] - '0';
int temperature = 0;
while(temsensor_num--){
temperature += (recv_message[p++] - '0')*10;
temperature += (recv_message[p++] - '0');
}
temperature /= (recv_message[5] - '0');
if(temperature > 18){
send_buf[6] = '0'; //门窗关闭
}
else{
send_buf[6] = '1'; //门窗打开
}
send_buf[7] = 'F';
send_buf[8] = 'F';
send_buf[9] = 'F';
}
send(s_accept,send_buf,100,0);
cout<
cout<<"发送成功"<
closesocket(s_server);
closesocket(s_accept);
//释放DLL资源
WSACleanup();
return 0;
}
5A00121723, 10
输入服务端消息
456
发送成功
输入服务端消息
*/
#include
#include
#include
#include
#include
#define random(a,b) (rand()%(b-a)+a)
#pragma comment(lib, "WS2_32")
using namespace std;
char send_buf[200]; //发送数据报
char accept_buf[200]; //接受数据报
string strtem(int i); //生成随机温度数据段
string strhum(int i); //生成随机湿度数据段
void tcpxy(); //生成上传服务器报文
void analysis(char receive[]); //对服务器传回的报文进行解析
{
WSADATA wsaData;
//WSADATA结构体中主要包含了系统所支持的Winsock版本信息 WSA API
if(WSAStartup(wsa, &wsaData)!=0)
{
cout<<"初始化失败"<
}
SOCKET s_server = socket(AF_INET, SOCK_STREAM, 0);
if(s_server==INVALID_SOCKET)
{
cout<<"socket创建失败"<
}
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.43.15"); //服务器IP
if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) //链接失败
{
cout << "server connnet fail!!" << endl;
WSACleanup();
return 0;
}
else
{
cout << "服务器连接成功!" << endl<
Sleep(1*1000);
cout<<"开始上传温度和湿度传感器信息..."<
{
cout<<"上传服务器报文为:"<
//cout<<"发送的"<
if(res_len<0)
{
cout<<"error"<
}
cout<<"报文发送成功,等待接受"<
cout<<"收到服务器端消息";
analysis(accept_buf);
Sleep(1*1000);
cout<
cout<<"收到服务器端消息";
analysis(accept_buf);
cout<<"------------------------------------------------"<
}
//释放DLL资源
WSACleanup();
return 0;
}
{
cout<<"传输的报文为:"<
if(receive[2]=='1')
{
cout<<"当前室内温度为:"<
else if(receive[2]=='0')
{
string strp1;
string strp2;
string strp3;
string strp4;
string strp5;
if(receive[7]=='1'&&receive[8]=='8')
strp3="温度为:18%";
else if(receive[7]=='3'&&receive[8]=='0')
strp3="湿度为:30%";
//cout<<"服务器发送的指令为:"<
{
strp1="空调";
if(receive[6]=='0')
{
strp2="制冷";
}
else if(receive[6]=='1')
{
strp2="制热";
}
else if(receive[6]=='2')
{
strp2="送风";
}
else if(receive[6]=='3')
{
strp2="提湿度";
}
else if(receive[6]=='4')
{
strp2="减湿度";
}
if(receive[9]=='0')
{
strp4="慢风速";
}
else if(receive[9]=='1')
{
strp4="中风速";
}
else if(receive[9]=='2')
{
strp4="高风速";
}
cout<
else if(receive[3]=='1')
{
strp1="门窗磁";
if(receive[6]=='0')
strp5="开窗";
else if(receive[6]=='1')
{
strp5="关窗";
}
cout<
}
}
void tcpxy()
{
// memset(accept_buf,0,sizeof(accept_buf));
int j=0;
srand((int)time(0)); // 产生随机种子 把0换成NULL也行
int devicebnum=random(0,2); //设备类型 0 温度,1 湿度
int tempnum=random(1,5);//温度反应器数量
int humnum=random(1,5);//湿度感应器数量
int startnum=random(1,5);
int direction=1;//1表示客户端到服务器,0表示服务器到客户端
string stableheader="5A";
if(startnum==1)
{
tempnum=random(1,5);
humnum=random(1,5);
}
else if(startnum==2)
{
tempnum=random(1,5);
humnum=random(1,5);
}
else if(startnum==3)
{
tempnum=random(1,3);
humnum=random(1,3);
}
else
{
tempnum=1;
humnum=1;
}
string str3 = to_string(devicebnum);
string str4 = to_string(tempnum);
string str5 = to_string(humnum);
string str6 = to_string(startnum);
string str7 = to_string(direction);
string str=stableheader+str7+str3+str6+str4; //帧格式:帧头+发送方向+设备类型+开始编号+数量+数据段
if(devicebnum==0)
str+=strtem(tempnum);
else if(devicebnum==1)
str+=strhum(tempnum);
cout<
send_buf[j]=str[i];
j++;
}
char qishi=send_buf[4];
char shebinum=send_buf[5];
// if(send_buf[3]=='0')
// {
// strp1="温度传感器温度分别为:";
// }
// else if(send_buf[3]=='1')
// {
// strp1="湿度传感器湿度分别为:"
// }
// cout<<"当前房间"+strp1+
}
string strtem(int i)//生成随机温度数据段
{
int temperature;
string str;
for(int j=0; j {
temperature=random(15,26);//产生随机温度。
str+=to_string(temperature);
}
return str;
}
string strhum(int i)//生成随机湿度数据段
{
int humidity;
string str;
for(int j=0; j {
humidity=random(25,46);//产生随机湿度。
str+=to_string(humidity);
}
return str;
}