|
|
@@ -6,18 +6,17 @@
|
|
|
#include <errno.h>
|
|
|
#include <sys/select.h>
|
|
|
#include <sys/time.h>
|
|
|
+#include <pthread.h>
|
|
|
|
|
|
#define BUFFER_SIZE 1024
|
|
|
|
|
|
+int mode = 0;
|
|
|
+int fd = 0;
|
|
|
+int thread_run = 1;
|
|
|
void print_usage(const char *prog_name)
|
|
|
{
|
|
|
- fprintf(stderr, "使用方法: %s <mode> <device>\n", prog_name);
|
|
|
- fprintf(stderr, " mode: 1 - 阻塞方式读取\n");
|
|
|
- fprintf(stderr, " 0 - 非阻塞方式读取\n");
|
|
|
- fprintf(stderr, " device: 字符设备路径 (例如: /dev/cash0)\n");
|
|
|
- fprintf(stderr, "示例:\n");
|
|
|
- fprintf(stderr, " %s 1 /dev/cash0 # 阻塞方式读取\n", prog_name);
|
|
|
- fprintf(stderr, " %s 0 /dev/cash0 # 非阻塞方式读取\n", prog_name);
|
|
|
+ printf("%s 1 /dev/cashd0\n", prog_name);
|
|
|
+ printf("%s 0 /dev/cashd0\n", prog_name);
|
|
|
}
|
|
|
|
|
|
int set_nonblocking(int fd)
|
|
|
@@ -56,28 +55,29 @@ int set_blocking(int fd)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-// 使用 select 实现阻塞读取
|
|
|
void blocking_read(int fd)
|
|
|
{
|
|
|
fd_set read_fds;
|
|
|
+ struct timeval tv;
|
|
|
char buffer[BUFFER_SIZE];
|
|
|
int ret;
|
|
|
|
|
|
- printf("阻塞模式:等待数据...\n");
|
|
|
+ printf("wait data...\n");
|
|
|
|
|
|
- while (1)
|
|
|
+ while (thread_run)
|
|
|
{
|
|
|
FD_ZERO(&read_fds);
|
|
|
FD_SET(fd, &read_fds);
|
|
|
+ tv.tv_sec = 1;
|
|
|
+ tv.tv_usec = 0;
|
|
|
|
|
|
- // NULL 表示无限等待,直到有数据可读
|
|
|
- ret = select(fd + 1, &read_fds, NULL, NULL, NULL);
|
|
|
+ ret = select(fd + 1, &read_fds, NULL, NULL, &tv);
|
|
|
|
|
|
if (ret == -1)
|
|
|
{
|
|
|
if (errno == EINTR)
|
|
|
{
|
|
|
- continue; // 被信号中断,继续等待
|
|
|
+ continue;
|
|
|
}
|
|
|
perror("select error");
|
|
|
break;
|
|
|
@@ -91,19 +91,18 @@ void blocking_read(int fd)
|
|
|
if (n > 0)
|
|
|
{
|
|
|
buffer[n] = '\0';
|
|
|
- printf("读到 %zd 字节: %s\n", n, buffer);
|
|
|
+ printf("read %zd byte: %s\n", n, buffer);
|
|
|
|
|
|
- // 如果读到 "quit" 或 "exit" 则退出
|
|
|
if (strncmp(buffer, "quit", 4) == 0 ||
|
|
|
strncmp(buffer, "exit", 4) == 0)
|
|
|
{
|
|
|
- printf("收到退出命令\n");
|
|
|
+ printf("exit\n");
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
else if (n == 0)
|
|
|
{
|
|
|
- printf("设备已关闭 (EOF)\n");
|
|
|
+ printf("close\n");
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
@@ -118,7 +117,6 @@ void blocking_read(int fd)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 使用 select 实现非阻塞读取(带超时检测)
|
|
|
void nonblocking_read(int fd)
|
|
|
{
|
|
|
fd_set read_fds;
|
|
|
@@ -126,87 +124,100 @@ void nonblocking_read(int fd)
|
|
|
char buffer[BUFFER_SIZE];
|
|
|
int ret;
|
|
|
|
|
|
- printf("非阻塞模式:\n");
|
|
|
-
|
|
|
- while (1)
|
|
|
+ while (thread_run)
|
|
|
{
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
ssize_t n = read(fd, buffer, sizeof(buffer) - 1);
|
|
|
|
|
|
if (n > 0)
|
|
|
{
|
|
|
- printf("读到 %zd 字节: %s\n", n, buffer);
|
|
|
+ printf("read %zd byte: %s\n", n, buffer);
|
|
|
}
|
|
|
sleep(1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void *read_pthread_func(void *arg)
|
|
|
+{
|
|
|
+ if (mode == 0)
|
|
|
+ {
|
|
|
+ if (set_nonblocking(fd) < 0)
|
|
|
+ {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ nonblocking_read(fd);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (set_blocking(fd) < 0)
|
|
|
+ {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ blocking_read(fd);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
int main(int argc, char *argv[])
|
|
|
{
|
|
|
- int mode;
|
|
|
const char *device_path;
|
|
|
- int fd;
|
|
|
int open_flags;
|
|
|
+ int ret = 0;
|
|
|
+ char cmd = 0;
|
|
|
+ pthread_t read_thread = 0;
|
|
|
|
|
|
- // 检查参数
|
|
|
if (argc != 3)
|
|
|
{
|
|
|
print_usage(argv[0]);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
- // 解析模式
|
|
|
mode = atoi(argv[1]);
|
|
|
if (mode != 0 && mode != 1)
|
|
|
{
|
|
|
- fprintf(stderr, "错误: mode 必须是 0 或 1\n");
|
|
|
print_usage(argv[0]);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
device_path = argv[2];
|
|
|
-
|
|
|
- // 打开设备
|
|
|
- // 注意:select 对常规文件总是返回可读,但对字符设备通常能正确工作
|
|
|
- // 为了更好的演示,我们以读写方式打开
|
|
|
open_flags = O_RDWR;
|
|
|
|
|
|
fd = open(device_path, open_flags);
|
|
|
if (fd < 0)
|
|
|
{
|
|
|
- perror("打开设备失败");
|
|
|
- fprintf(stderr, "设备: %s\n", device_path);
|
|
|
+ perror("open fail:");
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
- printf("成功打开设备: %s\n", device_path);
|
|
|
+ pthread_create(&read_thread, NULL, read_pthread_func, NULL);
|
|
|
|
|
|
- // 根据模式设置阻塞/非阻塞
|
|
|
- if (mode == 0)
|
|
|
+
|
|
|
+ while(1)
|
|
|
{
|
|
|
- // 非阻塞模式:设置 O_NONBLOCK 标志
|
|
|
- if (set_nonblocking(fd) < 0)
|
|
|
+ printf("please input cmd: o/O-open q-quit\n");
|
|
|
+ scanf(" %c", &cmd);
|
|
|
+
|
|
|
+ if (cmd == 'o' || cmd == 'O')
|
|
|
{
|
|
|
- close(fd);
|
|
|
- return 1;
|
|
|
+ ret = write(fd, &cmd, 1);
|
|
|
+ if (ret < 0)
|
|
|
+ {
|
|
|
+ perror("write fail:");
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
- printf("设置为非阻塞模式\n");
|
|
|
- nonblocking_read(fd);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // 阻塞模式:确保清除 O_NONBLOCK 标志
|
|
|
- if (set_blocking(fd) < 0)
|
|
|
+ else if( cmd == 'q')
|
|
|
{
|
|
|
- close(fd);
|
|
|
- return 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ printf("input error\n");
|
|
|
}
|
|
|
- printf("设置为阻塞模式\n");
|
|
|
- blocking_read(fd);
|
|
|
}
|
|
|
+ thread_run = 0;
|
|
|
+ pthread_join(read_thread, NULL);
|
|
|
|
|
|
close(fd);
|
|
|
- printf("程序退出\n");
|
|
|
|
|
|
return 0;
|
|
|
-}
|
|
|
+}
|