ZBLOG

非阻塞模式下,那这个程序中也没有配置为非阻塞呀?read默认是非阻塞嘛?

read 函数在默认情况下是阻塞的,这意味着如果没有可读取的数据,调用 read 会一直等待直到有数据可用。如果你想将 TUN 设备设置为非阻塞模式,你需要使用 fcntl 函数来修改文件描述符的属性。

以下是如何将 TUN 接口设置为非阻塞模式的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
#include <linux/if_tun.h>

// 定义缓冲区大小
#define BUF_SIZE 2048

// 函数用于设置 TUN 接口
int tun_alloc(char *dev) {
    struct ifreq ifr;
    int fd, err;

    // 打开 /dev/net/tun 设备
    fd = open("/dev/net/tun", O_RDWR);
    if (fd < 0) {
        perror("Opening /dev/net/tun");
        return fd;
    }

    memset(&ifr, 0, sizeof(ifr));
    
    // 设置为 TUN 接口
    ifr.ifr_flags = IFF_TUN | IFF_NO_PI; 

    // 如果指定了 dev 名称,则设置它
    if (*dev && (strlen(dev) > IFNAMSIZ)) {
        close(fd);
        errno = EINVAL;
        return -1;
    }
    
    strncpy(ifr.ifr_name, dev, IFNAMSIZ);

    // 创建 TUN 接口
    err = ioctl(fd, TUNSETIFF, (void *) &ifr);
    if (err < 0) {
        perror("ioctl(TUNSETIFF)");
        close(fd);
        return err;
    }

    return fd; // 返回文件描述符
}

// 将文件描述符设置为非阻塞模式
int set_nonblocking(int fd) {
   int flags = fcntl(fd, F_GETFL, 0);
   if (flags == -1) {
       return -1;
   }
   return fcntl(fd, F_SETFL, flags | O_NONBLOCK); 
}

// 读取数据的线程函数
void *read_tun(void *arg) {
    int tun_fd = *(int *)arg;
    char buffer[BUF_SIZE];

    while (1) {
        int nread = read(tun_fd, buffer, sizeof(buffer));

        if (nread < 0) {
            // 根据 errno 判断具体的错误情况
            if (errno == EINTR) {
                // 被信号中断,继续下一次读取尝试
                continue;
            } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 非阻塞模式下无数据可读,稍等再尝试或处理其他逻辑。
                usleep(100000); // 等待100毫秒再重试(可调整)
                continue;
            } else {
                perror("Read error");
                break; // 对于其他致命错误,退出循环
            }
        } else if (nread == 0) {
            printf("EOF reached\n");
            break; 
        } else {
            // 在此处理读取到的数据,例如打印出来或者转发等
            printf("Read %d bytes\n", nread);
            // 此处可以根据需要处理数据...
        }
        
        // 可以添加其他逻辑,比如睡眠或检查退出条件等。
   }

   return NULL;
}

int main() {
   char *dev = "tun0"; 

   int tun_fd = tun_alloc(dev);

   if (tun_fd < 0) {
       fprintf(stderr, "Error creating TUN interface\n");
       exit(1);
   }

   // 设置非阻塞模式
   if(set_nonblocking(tun_fd) != 0){
       perror("Failed to set non-blocking mode");
       close(tun_fd);
       exit(1);
   }

   pthread_t read_thread;

   // 创建线程来读取 TUN 数据包
   if(pthread_create(&read_thread, NULL, read_tun, &tun_fd)) {
       perror("Failed to create thread");
       close(tun_fd);
       exit(1);
   }

   pthread_join(read_thread, NULL); // 等待读线程结束

   close(tun_fd); // 清理资源

   return 0;
}

修改要点:

  • 增加了一个 set_nonblocking 函数,用于将指定的文件描述符设置为非阻塞模式。通过使用 fcntl 系统调用来获取和修改文件状态标志。
  • 在主函数中调用 set_nonblocking(tun_fd) 来将创建的 TUN 文件描述符设为非阻塞。

通过这种方式,当没有数据可读时,程序不会被卡住,而是会立即返回,并且可以处理其他任务或稍后再尝试读取。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:http://sdn.0voice.com/?id=7503

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?