智能家居 (7) ——网络服务器线程控制

目录

  • 网络线程控制代码
    • inputCommand.h
    • mainPro.c
    • socketControl.c
  • 代码测试
  • 往期文章

网络线程控制代码

inputCommand.h

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


struct Command
{
	char commandName[128];						//“控制方式”名
	char deviceFilesName[128];					//存放初始化所需文件的路径
	char command[32];							//存放指令
	int fd;										//存放文件描述符(串口/网络)
	int (*Init)(struct Command *file);			//“初始化”函数指针
	int s_fd;									//存放服务器套接字描述符
	char ipAdress[32];							//存放 IP地址
	char port[12];								//存放端口号
	int (*getCommand)(struct Command *cmd);		//“获取指令”函数指针

	struct Command *next;
};

struct Command *addSocketControlToCommandLink(struct Command *phead);		//“网络控制”加入指令链表函数声明

mainPro.c

#include 
#include 
#include "inputCommand.h"
#include 
#include 

struct Command *findCommandByName(char *name,struct Command *phead);		//寻找链节函数声明
void *socketControlThread(void *data);			//“网络控制”线程函数声明
void *socketReadThread(void *data);				//“读取端口”线程函数声明

struct Command *cmdhead = NULL;					//创建“指令”链表全局变量
struct Command *socketHandler = NULL;			//创建“链节处理”全局变量

int main()
{
	cmdhead = addSocketControlToCommandLink(cmdhead);		//“网络控制”对象加入链表

	pthread_t socketControl_thread;
	pthread_create(&socketControl_thread,NULL,socketControlThread,NULL);	//创建“网络控制”线程

	pthread_join(socketControl_thread, NULL);		//主函数等待“网络控制”线程退出
	return 0;
}

void *socketControlThread(void *data)				//“网络控制”线程
{
	int c_fd;											//文件描述符
	struct sockaddr_in c_addr;
	memset(&c_addr,0,sizeof(struct sockaddr_in));
	socklen_t clen = sizeof(struct sockaddr_in);
	pthread_t socketRead_thread;						//存放线程 ID


	socketHandler = findCommandByName("socketControl",cmdhead);			//寻找并返回“网络控制”所处链节
	if(socketHandler == NULL){											//若找不到
		printf("find socketHandler error\n");
		pthread_exit(NULL);
	}
	if(socketHandler->Init(socketHandler) < 0){							//执行“网络控制”功能初始化函数
		printf("socketControl init error\n");
		pthread_exit(NULL);
	}


	while(1){//不断等待连接 只要有连接进来,就创建线程去对接
		c_fd = accept(socketHandler->s_fd,(struct sockaddr*)&c_addr,&clen);		//接收连接请求
		socketHandler->fd = c_fd;												//发送文件描述符

		pthread_create(&socketRead_thread,NULL,socketReadThread,NULL);			//创建“读取端口”线程 连接一个客户端就去对接 可接纳10个客户端
	}
}
//创建新线程:用于读取TCP端口指令
//只要有连接,就创建线程去对接。线程共用内存资源,同一时刻,所有设备只有一种状态。也可PV操作
//所有线程 只操控一个结构体 再新来一个线程(新手机客户端接入) 前一个客户端失效 因为c_fd被改了。fork()可实现多个客户端同时控制
//不过好像寄存器和内存不是完全同步的 可能缓存没改?还可以多个客户端同时控制?
//如果直接把socketReadThread()拿过来循环的话,则同时刻不能接受新的客户端接入了,因为循环卡在了socketReadThread()函数里面了


//“读取端口”线程
void *socketReadThread(void *data)	//实际没传参			
{
	int nread;
	memset(socketHandler->command,'\0',sizeof(socketHandler->command));		//每次读取前,清空 “command(存放指令)”
	nread = read(socketHandler->fd,socketHandler->command,sizeof(socketHandler->command));		//读取客户端并存放到 “command”
	if(nread == 0){
		printf("No command received\n");
	}else{
		printf("Get command:%s\n",socketHandler->command);			//读取成功,打印数据
	}
}

struct Command *findCommandByName(char *name,struct Command *phead)			//通过“名字”寻找链节函数
{
	struct Command *tmp = phead;

	if(phead == NULL){
		return NULL;
	}

	while(tmp != NULL){
		if(strcmp(name,tmp->commandName) == 0){
			return tmp;
		}
		tmp = tmp->next;
	}
	return NULL;
}

socketControl.c

#include "inputCommand.h"
#include 
#include 
#include 
#include 
#include 
#include 


int socketControlInit(struct Command *file);						//“网络控制”功能初始化函数声明
struct Command *addSocketControlToLink(struct Command *phead);		//“网络控制”(对象)加入指令链表函数声明


struct Command socketControl = {				//定义“网络控制”对象
	.commandName = "socketControl",				//名字
	.command = {'\0'},							//初始化储存“指令”的空间
	.Init = socketControlInit,					//指定“网络控制”功能初始化函数
	.ipAdress = "192.168.0.19",				    //树莓派 IP地址
	.port = "8088",								//打开的端口号
};

int socketControlInit(struct Command *file)
{
	int s_fd;											//套接字描述符
	struct sockaddr_in s_addr;
	memset(&s_addr,0,sizeof(struct sockaddr_in));

	s_fd = socket(AF_INET,SOCK_STREAM,0);				//创建套接字
    if(s_fd == -1){										//若创建套接字失败
            perror("socketControl error");
            exit(-1);
    }

	s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(atoi(file->port));
    inet_aton(file->ipAdress,&s_addr.sin_addr);
	if(bind(s_fd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr_in)) == -1){		//套接字与端口号绑定
    	perror("bind error");
    	exit(-1);
    }

	if(listen(s_fd,10) == -1){							//打开监听
    	perror("listen error");
    	exit(-1);
    }

	file->s_fd = s_fd;									//发送套接字描述符
}

struct Command *addSocketControlToCommandLink(struct Command *phead)		//“网络控制”(对象)加入指令链表函数
{
	if(phead == NULL){
		return &socketControl;
	}else{
		socketControl.next = phead;
		phead = &socketControl;
		return phead;
	}
}

代码测试

手机下载网络调试助手,和树莓派连入同一个WIFI,输入树莓派IP地址以及端口号,发送消息:Today is 520,树莓派接收消息成功。

智能家居 (7) ——网络服务器线程控制_第1张图片

在这里插入图片描述

往期文章

智能家居 (1) ——智能家居整体功能框架
智能家居 (2) ——设计模式的引入
智能家居 (3) ——工厂模式继电器控制灯
智能家居 (4) ——工厂模式火焰报警
智能家居 (5) —— LD3320语音模块二次开发
智能家居 (6) ——语音识别线程控制
智能家居 (7) ——网络服务器线程控制
智能家居 (8) ——智能家居项目整合(网络控制线程、语音控制线程,火灾报警线程)
网络编程知识预备(1) ——了解OSI网络模型
网络编程知识预备(2) ——浅显易懂的三次握手与四次挥手
网络编程知识预备(3) ——SOCKET、TCP、HTTP之间的区别与联系
网络编程知识预备(4) ——了解HTTP协议与HTTPS协议
网络编程知识预备(5) ——libcurl库简介及其编程访问百度首页
智能家居 (9) ——人脸识别摄像头安装实现监控功能
智能家居 (10) ——人脸识别祥云平台编程使用
智能家居 (11) ——树莓派摄像头捕捉人脸并识别
智能家居 (12) ——人脸识别整合到智能家居系统
智能家居 (13) ——智能家居加入手机app端控制

你可能感兴趣的:(智能家居,物联网,c语言,智能家居,网络编程,多线程)