目录
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 131
typedef 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_var
def send_handle(window, client_socket, values):
global_var.TX_BUF = values['txbuff']
print(f"txbuff={global_var.TX_BUF}")
# 清理input
window['txbuff'].update(value='')
data = global_var.TX_BUF
client_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_BUF
client_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'+message
elif device == 'sr501':
global_var.TX_BUF = '@001'
elif device == 'irda':
global_var.TX_BUF = '@003'
elif device == 'motor':
global_var.TX_BUF = '@004'+message
elif device == 'dht11':
global_var.TX_BUF = '@005'+message
print(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_BUF
if len(cmd) < 4:
print("cmd ERROR")
return -1
if '@' == cmd[0]:
# 目前驱动设备数量只有两位数
if cmd[1] == '0':
#LED
if 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")
#SR501
elif cmd[2] == '0' and cmd[3] == '1':
if cmd[4] == '1':
print("有人")
elif cmd[4] == '0':
print("无人")
else:
print("message ERROR")
#SR04
elif cmd[2] == '0' and cmd[3] == '2':
print(cmd[4:])
#irda
elif cmd[2] == '0' and cmd[3] == '3':
print(cmd[4:])
#motor
elif cmd[2] == '0' and cmd[3] == '4':
print(cmd[4:])
#dht11
elif cmd[2] == '0' and cmd[3] == '5':
print(cmd[4:])
global_var.TEM=cmd[4]+cmd[5]
global_var.HUM=cmd[6]+cmd[7]
#ds18b20
elif cmd[2] == '0' and cmd[3] == '6':
print(cmd[4:])
#iic
elif cmd[2] == '0' and cmd[3] == '7':
print(cmd[4:])
#spi
elif 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.............")
break
elif event is None:
print(f"xxxxxxxxxxxxxxxxxxxx")
break
elif event == 'LED':
if led % 2 == 0:
set_tx_buf('led','p1')
else:
set_tx_buf('led','p0')
led+=1
if led > 100:
led = 0
send_cmd(client_socket)
# 处理其他事件...
except Exception as e:
window.close()
print(f"An error occurred: {e}")
return 0
window.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)