linux c select同时监听串口、网口(UDP)数据保存到文件

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define ERRORLOG(msg)                                       \
    do                                                      \
    {                                                       \
        printf("%s:%s:%d\n", __FILE__, __func__, __LINE__); \
        perror(msg);                                        \
    } while (0);
#define BUFFER_SIZE 1024
#define FILEIDNAME "fileid.txt"
#define OUTDATADIR "data"
#define CLIENT_IP "192.168.1.3"
#define CLIENT_PORT 8000
#define BUFFER_SIZE 1024

int ReadLogFileId(void)
{

    FILE *file;
    int number = 0;
    struct stat buffer;

    // 检查文件是否存在
    if (stat(FILEIDNAME, &buffer) != 0) // 不存在创建
    {
        char cmd[100] = {0};
        sprintf(cmd, "echo 0 > %s", FILEIDNAME);
        int ret = system(cmd);
        if (ret != 0)
        {
            ERRORLOG("system error");
        }
    }

    // 打开文件
    file = fopen(FILEIDNAME, "r");
    if (file == NULL)
    {
        ERRORLOG("open file error");
        return -1;
    }

    // 读取数字
    if (fscanf(file, "%d", &number) != 1)
    {
        ERRORLOG("read file id error");
        fclose(file);

        return -1;
    }
    if (number >= 50)
    {
        number = 0;
    }

    number += 1;
    file = fopen(FILEIDNAME, "w");
    if (file == NULL)
    {
        ERRORLOG("updata fileid error");
        return -1;
    }
    else
    {
        fprintf(file, "%d", number);
    }

    // 关闭文件
    fclose(file);
    return number;
}
// 输出目录
void IfExistOutDataDir(void)
{
    struct stat st = {0};
    if (stat(OUTDATADIR, &st) == -1)
    {
        char cmd[100] = {0};
        sprintf(cmd, "mkdir %s", OUTDATADIR);
        system(cmd);
    }
}
int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop)
{
    struct termios newtio, oldtio;
    if (tcgetattr(fd, &oldtio) != 0)
    {
        perror("SetupSerial 1");
        return -1;
    }
    bzero(&newtio, sizeof(newtio));
    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag = ~CSIZE;

    switch (nBits)
    {
    case 7:
        newtio.c_cflag |= CS7;
        break;
    case 8:
        newtio.c_cflag |= CS8;
        break;
    }

    switch (nEvent)
    {
    case 'O': // 奇校验
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= PARODD;
        newtio.c_iflag |= (INPCK | ISTRIP);
        break;
    case 'E': // 偶校验
        newtio.c_iflag |= (INPCK | ISTRIP);
        newtio.c_cflag |= PARENB;
        newtio.c_cflag = ~PARODD;
        break;
    case 'N': // 无校验
        newtio.c_cflag = ~PARENB;
        break;
    }

    switch (nSpeed)
    {
    case 300:
        cfsetispeed(&newtio, B300);
        cfsetospeed(&newtio, B300);
        break;
    case 600:
        cfsetispeed(&newtio, B600);
        cfsetospeed(&newtio, B600);
        break;
    case 1200:
        cfsetispeed(&newtio, B1200);
        cfsetospeed(&newtio, B1200);
        break;
    case 2400:
        cfsetispeed(&newtio, B2400);
        cfsetospeed(&newtio, B2400);
        break;
    case 4800:
        cfsetispeed(&newtio, B4800);
        cfsetospeed(&newtio, B4800);
        break;
    case 9600:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    case 19200:
        cfsetispeed(&newtio, B19200);
        cfsetospeed(&newtio, B19200);
        break;
    case 38400:
        cfsetispeed(&newtio, B38400);
        cfsetospeed(&newtio, B38400);
        break;
    case 57600:
        cfsetispeed(&newtio, B57600);
        cfsetospeed(&newtio, B57600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    default:
        printf("sorry! [%d bps] is not support ,Set default 9600bps now!\n", nSpeed);
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }
    if (nStop == 1)
    {
        newtio.c_cflag &= ~CSTOPB;
    }
    else if (nStop == 2)
    {
        newtio.c_cflag |= CSTOPB;
    }
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 0;
    tcflush(fd, TCIFLUSH);
    if ((tcsetattr(fd, TCSANOW, &newtio)) != 0)
    {
        perror("com set error");
        return -1;
    }
    printf("uart init done!\n");
    return 0;
}

int main(int argc, char **argv)
{

    if (argc != 4)
    {
        printf("should inpurt [uartdev] [ip] [port]\n"); //./a.out /dev/ttyUSB0 192.168.1.3 6000
    }

    int fid = ReadLogFileId();
    IfExistOutDataDir();

    /**********************串口********************************************/
    char output_file_name[256] = {0};
    sprintf(output_file_name, "%s/%s%d%s", OUTDATADIR, "diff_data_", fid, ".txt");

    FILE *fp;
    if ((fp = fopen(output_file_name, "w+")) == NULL)
        ERRORLOG("fopen error");
    // char *serial_device = "/dev/ttyUSB0";
    char *serial_device = argv[1];
    int baudrate = 115200;
    int serial_fd = open(serial_device, O_RDWR | O_NOCTTY | O_NDELAY);
    if (serial_fd == -1)
    {
        ERRORLOG("Unable to open serial port");
        return 1;
    }
    int setret = set_opt(serial_fd, baudrate, 8, 'N', 1);
    if (setret == 0)
    {
        printf("open serial_device succesed !\n");
    }

    /*****************************网络配置********************************************************/
    char output_file_name_net[256] = {0};
    sprintf(output_file_name_net, "%s/%s%d%s", OUTDATADIR, "imu_data_", fid, ".txt");

    FILE *fp1;
    if ((fp1 = fopen(output_file_name_net, "w+")) == NULL)
        ERRORLOG("fopen error");

    int sockfd;
    struct sockaddr_in server_addr, client_addr;
    char buffer[BUFFER_SIZE];
    socklen_t server_addr_size = sizeof(server_addr);

    // 创建UDP套接字
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        ERRORLOG("socket() error");
    }

    // 设置客户端地址结构
    memset(&client_addr, 0, sizeof(client_addr));
    client_addr.sin_family = AF_INET;
    client_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 接受任意IP
    client_addr.sin_port = htons(CLIENT_PORT);

    // 绑定套接字到客户端地址
    if (bind(sockfd, (struct sockaddr *)&client_addr, sizeof(client_addr)) == -1)
    {
        ERRORLOG("bind() error");
    }

    printf("UDP Client is running. Waiting for messages...\n");

    fd_set read_fds;
    int max_fd = (sockfd > serial_fd) ? sockfd : serial_fd;
    char readBuffer[BUFFER_SIZE] = {0};     // 用于每次存储读取的数据
    char readBuffer_net[BUFFER_SIZE] = {0}; // 用于每次存储读取的数据
    int uart_bytes = 0;
    int net_bytes = 0;
    int flag = 1;
    while (1)
    {
        // if (flag == 1)
        // {
        //     // 连上后给服务器发送消息,使服务端保存客户端网络信息便于回复
        //     if (-1 == sendto(sockfd, "hello", 6, 0, (struct sockaddr *)&client_addr, server_addr_size))
        //     {
        //         ERRORLOG("send error");
        //     }
        //     flag = 0;
        // }

        FD_ZERO(&read_fds);
        FD_SET(sockfd, &read_fds);    // 添加 TCP 套接字
        FD_SET(serial_fd, &read_fds); // 添加串口
        // 使用 select 等待数据
        int activity = select(max_fd + 1, &read_fds, NULL, NULL, NULL);
        if (activity < 0)
        {
            ERRORLOG("select error");
            break;
        }
        // 检查串口是否可读
        if (FD_ISSET(serial_fd, &read_fds))
        {
            uart_bytes = read(serial_fd, readBuffer, sizeof(readBuffer));

            if (uart_bytes > 0)
            {
                size_t write_count = fwrite(readBuffer, 1, uart_bytes, fp);
                if (write_count < uart_bytes)
                {
                    ERRORLOG("fwrite error");
                }
                fflush(fp); // 刷新文件缓冲区
                memset(readBuffer, 0, sizeof(readBuffer));
                uart_bytes = 0;
            }
        }

        // 检查 UDP 套接字是否可读
        if (FD_ISSET(sockfd, &read_fds))
        {
            // 接收应答消息  无需再次保存服务器的网络信息结构体了
            // 因为我们的 serveraddr  一直没动过

            net_bytes = recvfrom(sockfd, readBuffer_net, sizeof(readBuffer_net), 0, NULL, NULL);
            if (net_bytes == -1)
            {
                ERRORLOG("recv error");
            }
            printf("%s\n", readBuffer_net);

            if (net_bytes > 0)
            {
                size_t write_count = fwrite(readBuffer_net, 1, net_bytes, fp1);
                if (write_count < net_bytes)
                {
                    ERRORLOG("fwrite error");
                }

                fflush(fp1); // 刷新文件缓冲区
                memset(readBuffer_net, 0, sizeof(readBuffer_net));
                net_bytes = 0;
            }
            else
            {
                printf("UDP 连接关闭。\n");
                break;
            }
        }
    }

    return 0;
}

另附udp网络编程:

说明:两台主机(客户端和服务端在同一网段,服务端ip:192.168.1.2:6000,客户端192.168.1.3:8000),服务端向指定客户端的ip和端口发送数据:

udpserver.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define SERVER_IP "192.168.1.2"
#define SERVER_PORT 6000
#define CLIENT_IP "192.168.1.3"
#define CLIENT_PORT 8000
#define BUFFER_SIZE 1024

void error_handling(char *message);

int main(int argc, char *argv[]) {
    int sock;
    struct sockaddr_in server_addr, client_addr;
    char message[BUFFER_SIZE];
    socklen_t client_addr_size = sizeof(client_addr);

    // 创建UDP套接字
    sock = socket(PF_INET, SOCK_DGRAM, 0);
    if (sock == -1) {
        error_handling("socket() error");
    }

    // 设置服务端地址结构
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    server_addr.sin_port = htons(SERVER_PORT);

    // 绑定套接字到服务端地址
    if (bind(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        error_handling("bind() error");
    }

    // 设置客户端地址结构
    memset(&client_addr, 0, sizeof(client_addr));
    client_addr.sin_family = AF_INET;
    client_addr.sin_addr.s_addr = inet_addr(CLIENT_IP);
    client_addr.sin_port = htons(CLIENT_PORT);

    while (1) {
        printf("Input message to send: ");
        fflush(stdout); // 清空stdout缓冲区,确保立即打印提示信息
        fgets(message, BUFFER_SIZE, stdin); // 从标准输入读取消息

        // 发送消息到客户端
        if (sendto(sock, message, strlen(message), 0, (struct sockaddr*)&client_addr, client_addr_size) == -1) {
            error_handling("sendto() error");
        }
    }

    close(sock);
    return 0;
}

void error_handling(char *message) {
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define CLIENT_IP "192.168.1.3"
#define CLIENT_PORT 8000
#define BUFFER_SIZE 1024

void error_handling(char *message);

int main(int argc, char *argv[]) {
    int sock;
    struct sockaddr_in server_addr, client_addr;
    char buffer[BUFFER_SIZE];
    socklen_t server_addr_size = sizeof(server_addr);

    // 创建UDP套接字
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock == -1) {
        error_handling("socket() error");
    }

    // 设置客户端地址结构
    memset(&client_addr, 0, sizeof(client_addr));
    client_addr.sin_family = AF_INET;
    client_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 接受任意IP
    client_addr.sin_port = htons(CLIENT_PORT);

    // 绑定套接字到客户端地址
    if (bind(sock, (struct sockaddr*)&client_addr, sizeof(client_addr)) == -1) {
        error_handling("bind() error");
    }

    printf("UDP Client is running. Waiting for messages...\n");

    while (1) {
        // 接收来自服务端的消息
        int str_len = recvfrom(sock, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&server_addr, &server_addr_size);
        if (str_len == -1) {
            error_handling("recvfrom() error");
        }

        buffer[str_len] = '\0'; // 确保字符串以NULL结尾
        printf("Message received: %s\n", buffer);
    }

    close(sock);
    return 0;
}

void error_handling(char *message) {
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值