Linux tail -n 命令 用C语言实现

要点即在于从文件末尾往前读

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(int argc,char *argv[])
{
    FILE *in;
    int count=0;
    int argvline;
    long int pos;
    char s[100];
    argvline=get_line(argc,argv);
    in=fopen(argv[argc-1],"r");
    if(in==NULL){
     perror("fopen");
     exit(EXIT_FAILURE);
    }
    fseek(in,0,SEEK_END);
    pos=ftell(in);
    //从后往前读的技巧就在这儿
    while(pos){
     fseek(in,--pos,SEEK_SET);
     if(fgetc(in)=='\n'){
      if(count++==argvline) break;
     }
    }//end while(pos)

    //当文件内行数不足指定输出的行数时,默认输出文件所有内容
    //注意,这儿一定的先--count,因为之前的循环内多加了
    if(--count!=argvline){
     // printf("\ncount=%d,argvline=%d\n",count,argvline);
     //直接定位到文件头
     fseek(in,0,SEEK_SET); 
    }
    while(fgets(s,sizeof(s),in)!=NULL){
       printf("%s",s);
    }

    fclose(in);
    return 0;
}//end main


int get_line(int argc,char *argv[])
{
 int line=10;
 int ch;
 //判断用户是否输入了 -n参数 
 //有的话即取用户的,否则用命令默认的10
 while((ch=getopt(argc,argv,"n:"))!=-1){
  line=atoi(argv[2]);
  break;
 }
// printf("%d",line);
 return line;
}

这里写图片描述

<think>我们将在Linux下使用C语言实现串口通信,包括以下核心部分: 1. 打开串口设备 2. 配置串口参数(波特率、数据位、停止位、校验位等) 3. 使用环形缓冲区(队列)作为收发数据的缓冲区 4. 创建读取线程,将串口接收到的数据存入接收环形缓冲区 5. 提供发送函数,将数据放入发送环形缓冲区,并实际发送(可以在主循环中发送,也可以使用单独的发送线程) 6. 主程序可以处理接收到的数据并发送数据 参考引用[1][2]中提到的struct termios结构体进行串口配置,引用[3][4]中的环形缓冲区实现。 具体步骤: 步骤1:打开串口设备 步骤2:配置串口参数 步骤3:实现环形缓冲区(接收和发送各一个) 步骤4:创建读取线程,不断读取串口数据并存入接收缓冲区 步骤5:提供发送接口,将数据写入发送缓冲区,并启动发送(可以立即发送或由另一个线程发送) 步骤6:主程序示例 注意:环形缓冲区需要是线程安全的,因为读取线程和主线程可能同时操作接收缓冲区,发送也可能由不同线程操作。 下面我们逐步实现:</think>### Linux下C语言实现带缓冲队列的串口通信 #### 1. **串口设备打开与配置** 使用`termios`结构体配置串口参数[^1][^2]: ```c #include <fcntl.h> #include <termios.h> #include <unistd.h> // 打开串口设备 int serial_open(const char* device) { int fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); if (fd < 0) { perror("Error opening serial port"); return -1; } fcntl(fd, F_SETFL, 0); // 恢复阻塞模式 return fd; } // 配置串口参数 int serial_config(int fd, int baud, int databits, char parity, int stopbits) { struct termios options; tcgetattr(fd, &options); // 设置波特率 speed_t speed; switch (baud) { case 9600: speed = B9600; break; case 19200: speed = B19200; break; case 38400: speed = B38400; break; case 115200: speed = B115200; break; default: speed = B9600; } cfsetispeed(&options, speed); cfsetospeed(&options, speed); // 设置数据位 options.c_cflag &= ~CSIZE; switch (databits) { case 5: options.c_cflag |= CS5; break; case 6: options.c_cflag |= CS6; break; case 7: options.c_cflag |= CS7; break; case 8: default: options.c_cflag |= CS8; } // 设置校验位 switch (parity) { case 'O': // 奇校验 options.c_cflag |= PARENB; options.c_cflag |= PARODD; break; case 'E': // 偶校验 options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; break; case 'N': // 无校验 default: options.c_cflag &= ~PARENB; } // 设置停止位 options.c_cflag &= ~CSTOPB; if (stopbits == 2) options.c_cflag |= CSTOPB; // 基本配置 options.c_cflag |= (CLOCAL | CREAD); // 本地连接,启用接收 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始输入模式 options.c_oflag &= ~OPOST; // 原始输出模式 options.c_cc[VMIN] = 0; // 最小读取字符数 options.c_cc[VTIME] = 10; // 读取超时(1秒) tcsetattr(fd, TCSANOW, &options); return 0; } ``` #### 2. **环形缓冲区实现** 参考引用[3][^3]实现线程安全的环形缓冲区: ```c #include <pthread.h> #define BUFFER_SIZE 1024 typedef struct { unsigned char buffer[BUFFER_SIZE]; int head; int tail; pthread_mutex_t lock; } RingBuffer; // 初始化缓冲区 void ringbuf_init(RingBuffer* rb) { rb->head = 0; rb->tail = 0; pthread_mutex_init(&rb->lock, NULL); } // 写入数据 int ringbuf_write(RingBuffer* rb, unsigned char data) { pthread_mutex_lock(&rb->lock); int next = (rb->head + 1) % BUFFER_SIZE; if (next == rb->tail) { // 缓冲区满 pthread_mutex_unlock(&rb->lock); return -1; } rb->buffer[rb->head] = data; rb->head = next; pthread_mutex_unlock(&rb->lock); return 0; } // 读取数据 int ringbuf_read(RingBuffer* rb, unsigned char* data) { pthread_mutex_lock(&rb->lock); if (rb->tail == rb->head) { // 缓冲区空 pthread_mutex_unlock(&rb->lock); return -1; } *data = rb->buffer[rb->tail]; rb->tail = (rb->tail + 1) % BUFFER_SIZE; pthread_mutex_unlock(&rb->lock); return 0; } // 获取缓冲区数据量 int ringbuf_count(RingBuffer* rb) { pthread_mutex_lock(&rb->lock); int count = (rb->head >= rb->tail) ? (rb->head - rb->tail) : (BUFFER_SIZE - rb->tail + rb->head); pthread_mutex_unlock(&rb->lock); return count; } ``` #### 3. **数据收发线程** ```c #include <pthread.h> RingBuffer rx_buf, tx_buf; // 接收线程函数 void* receive_thread(void* arg) { int fd = *((int*)arg); unsigned char ch; while (1) { int n = read(fd, &ch, 1); if (n > 0) { ringbuf_write(&rx_buf, ch); } usleep(10000); // 10ms延迟避免CPU过高 } return NULL; } // 发送线程函数 void* transmit_thread(void* arg) { int fd = *((int*)arg); unsigned char ch; while (1) { if (ringbuf_read(&tx_buf, &ch) == 0) { write(fd, &ch, 1); } else { usleep(5000); // 缓冲区空时短暂休眠 } } return NULL; } // 发送数据接口 void serial_send(int fd, const unsigned char* data, int len) { for (int i = 0; i < len; i++) { while (ringbuf_write(&tx_buf, data[i]) != 0) { usleep(1000); // 等待缓冲区空间 } } } ``` #### 4. **完整使用示例** ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> int main() { // 初始化缓冲区 ringbuf_init(&rx_buf); ringbuf_init(&tx_buf); // 打开并配置串口 int fd = serial_open("/dev/ttyUSB0"); if (fd < 0) return EXIT_FAILURE; // 配置: 115200波特率, 8数据位, 无校验, 1停止位 serial_config(fd, 115200, 8, 'N', 1); // 创建收发线程 pthread_t rx_tid, tx_tid; pthread_create(&rx_tid, NULL, receive_thread, &fd); pthread_create(&tx_tid, NULL, transmit_thread, &fd); // 主循环处理接收数据 unsigned char data; while (1) { int count = ringbuf_count(&rx_buf); if (count > 0) { printf("Received %d bytes: ", count); while (ringbuf_read(&rx_buf, &data) == 0) { printf("%02X ", data); // 十六进制显示 } printf("\n"); } // 示例: 每秒发送测试数据 static int counter = 0; unsigned char test_data[] = {0xAA, 0x55, counter++ % 256}; serial_send(fd, test_data, sizeof(test_data)); sleep(1); } close(fd); return EXIT_SUCCESS; } ``` #### 5. **关键配置参数对照表** | 参数 | 函数参数 | 可选值 | |--------------|----------------------|--------------------------------| | **波特率** | `baud` | 9600, 19200, 38400, 115200 | | **数据位** | `databits` | 5, 6, 7, 8 | | **校验位** | `parity` | 'N'(无), 'O'(奇), 'E'(偶) | | **停止位** | `stopbits` | 1, 2 | | **流控** | 需扩展 | 0=无, 1=RTS/CTS, 2=XON/XOFF | > **编译命令**:`gcc serial.c -o serial -lpthread` #### 6. **应用场景** 1. **工业设备监控**:实时采集传感器数据 2. **嵌入式开发**:与微控制器通信调试 3. **物联网网关**:连接LoRa/NB-IoT模块 4. **机器人控制**:发送运动指令和接收状态反馈
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值