目录
1、添加服务器中对客户端数据的具体分设备处理
2、实现将数组中的某些位数据转化为整型
3、修改client和server,互相可处理LED
4、结合驱动程序实现对物理设备的控制
4.1 增加驱动处理句柄
4.2 连接驱动处理句柄和tcp通讯接口
4.3 在client端做对应处理
4.4 成果展示
5、客户端添加对退出的处理
1、添加服务器中对客户端数据的具体分设备处理
#include "tcp.h"
#include "net.h"
#include "global.h"
#include "tool.h"
/*
*author : xintianyu
*return : err num
*data : 2024-4-10
-----------------------
*author : ???
*return : ???
*data : ???
*/
int usage(int argc, char *argv[])
{ if (argc != 3){ printf("Usage: %s <ip_address> <port>\n", argv[0]); return ERROR; }else{return NOERROR;}
}void do_nothing()
{/*void*/
}/*
*author : xintianyu
*return : err num
*data : 2024-4-10
-----------------------
*author : ???
*return : ???
*data : ???
*/
int tcp_server(int argc, char *argv[])
{int server_fd, client_fd; struct sockaddr_in server_addr, client_addr; socklen_t client_len = sizeof(client_addr); char *ip_address = argv[1]; int port = atoi(argv[2]); // 创建TCP套接字 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket creation failed"); exit(EXIT_FAILURE); } /*支持快速重新绑定*/int b_reuse = 1;setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));// 设置服务器地址信息 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(ip_address); server_addr.sin_port = htons(port); // 绑定套接字到服务器地址 if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // 监听套接字 if (listen(server_fd, 5) < 0) { perror("listen failed"); exit(EXIT_FAILURE); } printf("Server listening on %s:%d...\n", ip_address, port); //处理僵尸进程signal(SIGCHLD, SIG_IGN);// 接受客户端连接 if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len)) < 0) { perror("accept failed");goto err1;}// 打印客户端信息 char client_ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN); printf("Client connected from %s:%d\n", client_ip, ntohs(client_addr.sin_port));if (ERROR == do_client(client_fd)){perror("client disconnect.....");goto err2;}err2:close(client_fd);
err1:close(server_fd);return NOERROR;
}int do_client(int acceptfd)
{//MSG msg;char rx_buffer[BUFFER_SIZE];char tx_buffer[BUFFER_SIZE];int cmd;// 接收客户端消息memset(rx_buffer, 0, BUFFER_SIZE);memset(tx_buffer, 0, BUFFER_SIZE);while(1){ssize_t bytes_read = recv(acceptfd, rx_buffer, BUFFER_SIZE - 1, 0); if (bytes_read < 0) { perror("recv failed"); return ERROR;}else{/*确保消息以换行符结尾,并打印接收到的消息*/ if (bytes_read > 0 && rx_buffer[bytes_read - 1] != '\n') { rx_buffer[bytes_read] = '\n'; rx_buffer[bytes_read + 1] = '\0'; }if ('Q' == rx_buffer[0] || 0 == rx_buffer[0]){printf("client quit....\n");return ERROR;}else{cmd = select_driver(rx_buffer);}printf("cmd is %d\n", cmd);
#if (STD_ON == DEBUG)printf("Received message: %s", rx_buffer); // 回复客户端消息 //strcpy(tx_buffer, "Hello, client!\n");if (send(acceptfd, rx_buffer, strlen(rx_buffer), 0) < 0) { perror("send failed"); }
#endif/*STD_ON == DEBUG*/}}return NOERROR;
}int select_driver(char * cmd)
{int opt = 0;MSG drv_msg;if('@' == cmd[0]){
#if (STD_ON == DEBUG)printf("cmd[0] = @\n");
#endif/*STD_ON == DEBUG*/drv_msg.device = extract_digit_number(cmd, 1, 3);/*TODO 后续需升级为多线程模式调用驱动*/switch(drv_msg.device){case 0:printf("LED!!!\n");break;case 1:printf("SR501!!!\n");break;case 2:printf("SR04!!!\n");break;case 3:printf("IRDA!!!\n");break;case 4:printf("motor!!!\n");break;case 5:printf("dht11!!!\n");break;case 6:printf("ds18b20!!!\n");break;case 7:printf("IIC!!!\n");break;case 8:printf("SPI!!!\n");break;default:printf("Unknown equipment!!!\n");}}else{printf("cmd[0] ERROR!!!\n");opt = ERROR;}opt = atoi(&cmd[1]);return opt;
}
2、实现将数组中的某些位数据转化为整型
/*
*author : xintianyu
*function : main
*data : 2024-4-10
-----------------------
*author : ???
*return : ???
*data : ???
*/
int extract_digit_number(const char *str, int start_pos, const int size)
{/*有些版本的编译器规定数组下标必须为const类型*//*TODO 改为断言*/if (NULL == str || strlen(str) < start_pos + size) { return -1; // 字符串为空、长度不足或起始位置超出范围 }char chars[(size+1)];for (int i = 0; i < size; i++) { chars[i] = str[start_pos + i]; } chars[size] = '\0'; // 确保字符串正确结束 int num = 0; for (int i = 0; i < size; i++) { if (!isdigit(chars[i])) { return -1; // 包含非数字字符 } num = num * 10 + (chars[i] - '0'); } return num; // 返回转换后的整型数
}
3、修改client和server,互相可处理LED
服务器程序中我将debug关闭了改为直接由driver_select控制消息回传
客户端则是直接加上通用程序就好了
简单验证一下效果还不错
4、结合驱动程序实现对物理设备的控制
4.1 增加驱动处理句柄
/* * 文件名: driver_handle.c * 作者: 辛天宇 * 更新时间: 2024-04-16 * 软件版本号: 0.0.0*/
/**************************************************************
***************************INCLUDE*****************************
**************************************************************/
#include "driver_handle.h"
/**************************************************************
****************************EXTERN*****************************
**************************************************************/
/*
*author : xintianyu
*function : Handle led Settings
*data : 2024-4-10
-----------------------
author date modify*/
int led_handle(DIRECTION led_direction, CMD *cmd)
{char *device = "/dev/CEBSS_led";static int fd;int ret;char buf[2];/* 打开文件 */fd = open(device, O_RDWR);if (fd == -1){printf("can not open file /dev/CEBSS_led\n");return -1;}if (direction_put == led_direction){/* write */buf[0] = strtol(device, NULL, 0);if (cmd_open == *cmd)buf[1] = 0;if (cmd_close == *cmd)buf[1] = 1;ret = write(fd, buf, 2);}else if(direction_get == led_direction){buf[0] = strtol(device, NULL, 0);ret = read(fd, buf, 2);if (ret == 2){printf("led %d status is %s\n", buf[0], buf[1] == 0 ? "on" : "off");if (buf[1] == 0){*cmd = cmd_open;}else if (buf[1] == 1){*cmd = cmd_close;}}}else{printf("Undefined command\n");}close(fd);return NOERROR;
}
#ifndef _DRIVER_HANDLE_H_
#define _DRIVER_HANDLE_H_
#include "global.h"
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>#define LED_GPIO_0 131typedef int (*FUC_HANDLE)(void);/*TODO 很草需要完善*/
typedef enum {direction_get = 0,direction_put = 1,direction_num = 2,
}DIRECTION;typedef enum {cmd_open = 0,cmd_close = 1,cmd_get_value = 2,cmd_no = 3,cmd_num = 4,
}CMD;typedef struct {int gpio;char device_name[32];union { DIRECTION status;} led_direction; union { CMD command; } led_cmd;FUC_HANDLE handle;
} LED;typedef struct{LED led0;
}DRIVER;int led_handle(DIRECTION led_direction, CMD *cmd);#endif/*driver_handle.h*/
这里是一个对驱动控制的模板
4.2 连接驱动处理句柄和tcp通讯接口
/* TODO 传递参数后需改为使用通信结构体 */
int select_driver(char * cmd, int acceptfd)
{int opt = 0;MSG drv_msg;char *tx_buffer;DIRECTION direction;CMD drv_cmd;if('@' == cmd[0]){
#if (STD_ON == DEBUG)printf("cmd[0] = @\n");
#endif/*STD_ON == DEBUG*/drv_msg.device = extract_digit_number(cmd, 1, 3);printf("device is %d\n", drv_msg.device);/*TODO 后续需升级为多线程模式调用驱动*/switch(drv_msg.device){case 0:/*TODO 日志打印等级控制*//*TODO用设备结构体后这里要封装一下*/printf("LED!!!\n");if ('g' == cmd[4]){direction = direction_get;drv_cmd = cmd_no;led_handle(direction, &drv_cmd);if (cmd_close == drv_cmd){tx_buffer = "@000g0";}else if(cmd_open == drv_cmd){tx_buffer = "@000g1";}}else{if ('1' == cmd[5])drv_cmd = cmd_open;else if ('0' == cmd[5])drv_cmd = cmd_close;direction = direction_put;if (NOERROR == led_handle(direction, &drv_cmd)){tx_buffer = "@000p1";}else{tx_buffer = "@000p0";}} if (send(acceptfd, tx_buffer, strlen(tx_buffer), 0) < 0){perror("send failed"); }break;case 1:printf("SR501!!!\n");break;case 2:printf("SR04!!!\n");break;case 3:printf("IRDA!!!\n");break;case 4:printf("motor!!!\n");break;case 5:printf("dht11!!!\n");break;case 6:printf("ds18b20!!!\n");break;case 7:printf("IIC!!!\n");break;case 8:printf("SPI!!!\n");break;default:printf("Unknown equipment!!!\n");}}else{printf("cmd[0] ERROR!!!\n");opt = ERROR;}opt = atoi(&cmd[1]);return opt;
}
这里后面肯定要做相当多的优化暂时只是让他跑起来
4.3 在client端做对应处理
'''
fuction : 客户端程序
author : 辛天宇
date : 2024-4-13
-------------------------------
author date modify
辛天宇 2024-4-15 结合GUI和网络通信'''
import show
import tcp
import tool
import socket
import global_vardef send_handle(window, client_socket, values):global_var.TX_BUF = values['txbuff'] print(f"txbuff={global_var.TX_BUF}")# 清理inputwindow['txbuff'].update(value='')data = global_var.TX_BUFclient_socket.sendall(data.encode())# 接收服务器的响应data = client_socket.recv(512)# 将字节字符串转化为字符串global_var.RX_BUF = data.decode('utf-8')print(f"rx......{global_var.RX_BUF}") def quit_handel(client_socket):cmd='Q'client_socket.sendall(cmd.encode())tcp.disconnect_to_server(client_socket)# 进行一次发送和接收
def send_cmd(client_socket):data = global_var.TX_BUFclient_socket.sendall(data.encode())# 接收服务器的响应data = client_socket.recv(512)# 将字节字符串转化为字符串global_var.RX_BUF = data.decode('utf-8')# 设置发送消息
def set_tx_buf(device, message): if device == 'sr04':global_var.TX_BUF = '@002'if device == 'led':global_var.TX_BUF = '@000'+messageelif device == 'sr501':global_var.TX_BUF = '@001'elif device == 'irda':global_var.TX_BUF = '@003'elif device == 'motor':global_var.TX_BUF = '@004'+messageelif device == 'dht11':global_var.TX_BUF = '@005'+messageprint(f"dht11={global_var.TX_BUF}")elif device == 'ds18b20':global_var.TX_BUF = '@006'elif device == 'iic':global_var.TX_BUF = '@007'elif device == 'spi':global_var.TX_BUF = '@008'# 处理数据
def cmd_handle():cmd = global_var.RX_BUFif len(cmd) < 4:print("cmd ERROR")return -1if '@' == cmd[0]:# 目前驱动设备数量只有两位数if cmd[1] == '0':#LEDif cmd[2] == '0' and cmd[3] == '0':if cmd[5] == '1':print("LED Status change success")elif cmd[5] == '0':print("LED Status change failure")else:print("message ERROR")#SR501elif cmd[2] == '0' and cmd[3] == '1':if cmd[4] == '1':print("有人")elif cmd[4] == '0':print("无人")else:print("message ERROR")#SR04elif cmd[2] == '0' and cmd[3] == '2':print(cmd[4:])#irdaelif cmd[2] == '0' and cmd[3] == '3':print(cmd[4:])#motorelif cmd[2] == '0' and cmd[3] == '4':print(cmd[4:])#dht11elif cmd[2] == '0' and cmd[3] == '5':print(cmd[4:])global_var.TEM=cmd[4]+cmd[5]global_var.HUM=cmd[6]+cmd[7]#ds18b20elif cmd[2] == '0' and cmd[3] == '6':print(cmd[4:])#iicelif cmd[2] == '0' and cmd[3] == '7':print(cmd[4:])#spielif cmd[2] == '0' and cmd[3] == '8':print(cmd[4:])# 处理事件
def event_handle(window, client_socket):led = 0# 事件循环 while True: try:cmd_handle()event, values = window.read()if event == 'input':window['txbuff'].update(disabled=not values['input'])elif event == 'send':send_handle(window, client_socket, values)elif event == 'Clean':window['Output'].update(value='')elif event == 'dht11':set_tx_buf('dht11', '2525')send_cmd(client_socket)message = f"{global_var.TEM}°C {global_var.HUM}%"window['Getvalue'].update(message)elif event == 'ds18b20':set_tx_buf('ds18b20')send_cmd(client_socket)message = f"{global_var.TEM}°C"window['Getvalue'].update(message)elif event == 'Quit': quit_handel(client_socket) print(f"See you.............")breakelif event is None:print(f"xxxxxxxxxxxxxxxxxxxx")breakelif event == 'LED':if led % 2 == 0:set_tx_buf('led','p1')else:set_tx_buf('led','p0')led+=1if led > 100:led = 0send_cmd(client_socket)# 处理其他事件...except Exception as e:window.close()print(f"An error occurred: {e}")return 0window.close()return 0 def main():# 创建GUI对象window = show.show_window('DefaultNoMoreNagging')# 尝试连接到服务器 client_socket = tcp.connect_to_server()if client_socket is not None: event_handle(window, client_socket)if __name__ == '__main__':main()
4.4 成果展示
https://live.csdn.net/v/379386
5、客户端添加对退出的处理
def quit_handel(client_socket):cmd='Q'client_socket.sendall(cmd.encode())tcp.disconnect_to_server(client_socket)