Linux串口编程详解(阻塞模式、非阻塞模式、select函数)

news2025/1/16 16:07:13

前言:之前一直觉得串口编程很简单,这两天仔细研究后发现串口里的各种参数还挺复杂,稍不注意就容易出错,这里总结一下网上的各种文章及自己的理解与实践。

open 函数

功能描述:用于打开或创建文件,成功则返回文件描述符,否则返回-1,open返回的文件描述符一定是最小的未被使用的描述符

#include<fcntl.h>
int open(const char * pathname,int flags); 
int open(const char * pathname,int flags,mode_t mode);

参数flags:一些文件模式选择,有如下几个参数可以设置:

  • O_RDONLY 只读模式
  • O_WRONLY 只写模式
  • O_RDWR 读写模式

上面三个参数在设置的时候必须选择其中一个!下面的参数是可选的:

  • O_APPEND 每次操作都写入文件的末尾
  • O_CREAT 如果指定文件不存在,则创建这个文件
  • O_EXCL 如果要创建的文件已存在,则返回 -1,并且修改 errno 的值
  • O_TRUNC 如果文件存在,并且以只写/读写的方式打开,则清空文件全部内容
  • O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端
  • O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式
  • O_NDELAY 表示用于设置非阻塞方式。同时通知Linux系统,这个程序不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)。如果用户没有指定这个标志,则进程将会一直处在睡眠状态,直到DCD信号线被激活。

下面三个常量同样是选用的,他们用于同步输入输出:

  • O_DSYNC 等待物理 I/O 结束后再 write。在不影响读取新写入数据的前提下,不等待文件属性更新
  • O_RSYNC read等待所有写入同一区域的写操作完成后再进行
  • O_SYNC 等待物理 I/O 结束后再 write,包括更新文件属性的 I/O

对于串口的打开操作,必须使用O_NOCTTY参数,它表示打开的是一个终端设备,程序不会成为该端口的控制终端。如果不使用此标志,任务的一个输入(比如键盘终止信号等)都会影响进程。

open函数第三个参数mode为可选参数,表示打开文件权限

fcntl 函数

功能描述:根据文件描述词来操作文件的特性,返回-1代表出错

#include<unistd.h>
#include<fcntl.h>
int fcntl(int fd,int cmd);
int fcntl(int fd,int cmd,long arg);
int fcntl(int fd,int cmd,struct flock *lock);

fcntl()函数主要有5种功能:

  • 复制一个现有的描述符(cmd=F_DUPFD/F_DUPFD_CLOEXEC)
  • 获得/设置文件描述符标记(cmd=F_GETFD/F_SETFD)
  • 获得/设置文件状态标记(cmd=F_GETFL/F_SETFL) #常用
  • 获得/设置异步I/O所有权(cmd=F_GETOWN/F_SETOWN)
  • 获得/设置记录锁(cmd=F_GETLK/F_SETLK/F_SETLKW) #常用

F_SETFL :设置文件状态标志。其中O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_NOCTTY 和 O_TRUNC不受影响,

能更改的标志有 O_APPEND,O_ASYNC, O_DIRECT, O_NOATIME 和 O_NONBLOCK。此函数功能强大,在此不做详细叙述!

内核资料直通车:最新Linux内核源码资料文档+视频资料icon-default.png?t=M85Bhttps://link.zhihu.com/?target=https%3A//docs.qq.com/doc/DTmFTc29xUGdNSnZ2

学习直通车:Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈icon-default.png?t=M85Bhttps://link.zhihu.com/?target=https%3A//ke.qq.com/course/4032547%3FflowToken%3D1040236

串口参数初始化

串口参数由结构体termio设置:

struct termio
{ 
    unsigned short  c_iflag;    /* 输入模式标志 */  
    unsigned short  c_oflag;    /* 输出模式标志 */  
    unsigned short  c_cflag;    /* 控制模式标志*/   
    unsigned short  c_lflag;    /* local mode flags */   
    unsigned char   c_line;     /* line discipline */ 
    unsigned char   c_cc[NCC];  /* control characters */
};

这里列出常见配置:

int  set_port_attr(int fd,int  baudrate, int  databit, const char *stopbit, char parity, int vtime,int vmin )
{
    struct termios opt;
    tcgetattr(fd, &opt);       //获取初始设置
        
    set_baudrate(&opt, baudrate);
    set_data_bit(&opt, databit);
    set_parity(&opt, parity);
    set_stopbit(&opt, stopbit);
        
    opt.c_cflag &= ~CRTSCTS;   // 不使用硬件流控制
    opt.c_cflag |= CLOCAL | CREAD; //CLOCAL--忽略 modem 控制线,本地连线, 不具数据机控制功能, CREAD--使能接收标志 
 
    /*
    IXON--启用输出的 XON/XOFF 流控制
    IXOFF--启用输入的 XON/XOFF 流控制
    IXANY--允许任何字符来重新开始输出
    IGNCR--忽略输入中的回车
    */
    opt.c_iflag &= ~(IXON | IXOFF | IXANY);
    opt.c_oflag &= ~OPOST; //启用输出处理
    /*
    ICANON--启用标准模式 (canonical mode)。允许使用特殊字符 EOF, EOL,
        EOL2, ERASE, KILL, LNEXT, REPRINT, STATUS, 和 WERASE,以及按行的缓冲。
    ECHO--回显输入字符
    ECHOE--如果同时设置了 ICANON,字符 ERASE 擦除前一个输入字符,WERASE 擦除前一个词
    ISIG--当接受到字符 INTR, QUIT, SUSP, 或 DSUSP 时,产生相应的信号
    */
    opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); 
    opt.c_cc[VMIN] = vmin;   //设置非规范模式下的超时时长和最小字符数:阻塞模式起作用
    opt.c_cc[VTIME] = vtime; //VTIME与VMIN配合使用,是指限定的传输或等待的最长时间 单位:0.1S
        
    tcflush (fd, TCIFLUSH);                 /* TCIFLUSH-- update the options and do it NOW */
    return (tcsetattr (fd, TCSANOW, &opt)); /* TCSANOW--改变立即发生 */
}
 
 
static void set_baudrate(struct termios *opt, unsigned int baudrate)
{
    cfsetispeed(opt, baudrate);
    cfsetospeed(opt, baudrate);
}
 
static void set_stopbit(struct termios *opt, const char *stopbit)
{
    if (0 == strcmp (stopbit, "1")) {
        opt->c_cflag &= ~CSTOPB;                                                           /* 1位停止位t          */
    }else if (0 == strcmp (stopbit, "1.5")) {
        opt->c_cflag &= ~CSTOPB;                                                           /* 1.5位停止位         */
    }else if (0 == strcmp (stopbit, "2")) {
        opt->c_cflag |= CSTOPB;                                                            /* 2 位停止位          */
    }else {
        opt->c_cflag &= ~CSTOPB;                                                           /* 1 位停止位          */
    }
}
 
static void set_data_bit(struct termios *opt, unsigned int databit)
{
    opt->c_cflag &= ~CSIZE;
    switch (databit) {
    case 8:
        opt->c_cflag |= CS8;
    break;
    case 7:
        opt->c_cflag |= CS7;
    break;
    case 6:
        opt->c_cflag |= CS6;
    break;
    case 5:
        opt->c_cflag |= CS5;
    break;
    default:
        opt->c_cflag |= CS8;
    break;
    }
}
 
static void set_parity(struct termios *opt, char parity)
{
    switch (parity) {
    case 'N':                                                                                   /* 无校验          */
    case 'n':
        opt->c_cflag &= ~PARENB;
        break;
    case 'E':                                                                                   /* 偶校验          */
    case 'e':
        opt->c_cflag |= PARENB;
        opt->c_cflag &= ~PARODD;
        break;
    case 'O':                                                                                   /* 奇校验           */
    case 'o':
        opt->c_cflag |= PARENB;
        opt->c_cflag |= ~PARODD;
        break;
    case 'S':
    case 's':
        opt->c_cflag &= ~PARENB;                                                                 /*清除校验位   disable pairty checking Space校验  */
        opt->c_cflag &= ~CSTOPB;        
        opt->c_iflag |= INPCK;   
        break;
    default:                                                                                    /* 其它选择为无校验 */
        opt->c_cflag &= ~PARENB;
        break;
    }
}

阻塞式读写配置

打开时使用:
fd = open(USAR1, O_RDWR | O_NOCTTY );//阻塞式读写
 
打开后使用fcntl函数修改:
fcntl(fd, F_SETFL, 0); //设为阻塞

阻塞式读写可设置以下两参数:

opt.c_cc[VMIN] = vmin;   //设置非规范模式下的超时时长和最小字符数:阻塞模式起作用opt.c_cc[VTIME] = vtime; //VTIME与VMIN配合使用,是指限定的传输或等待的最长时间
  • 若 VMIN = 0 ,VTIME = 0 ,函数read未读到任何参数也立即返回,相当于非阻塞模式;
  • 若 VMIN = 0, VTIME > 0 ,函数read读取到数据立即返回,若无数据则等待VTIME时间返回;
  • 若 VMIN > 0, VTIME = 0 ,函数read()只有在读取到VMIN个字节的数据或者收到一个信号的时候才返回;
  • 若 VMIN > 0, VTIME > 0 ,从read读取第一个字节的数据时开始计时,并会在读取到VMIN个字节或者VTIME时间后返回。

非阻塞式读写配置

打开时使用

  • open(USAR1, O_RDWR | O_NOCTTY | O_NDELAY );//非阻塞式读写
  • open(USAR1, O_RDWR | O_NOCTTY | O_NONBLOCK);//非阻塞式读写
  • open(USAR1, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);//非阻塞式读写

打开后使用fcntl修改设置

fcntl(socket_descriptor, F_SETFL, flags | O_NONBLOCK); //设为非阻塞

O_NONBLOCK和O_NDELAY都是设置为非阻塞模式,但是它们有些差别,O_NDELAY会使I/O函式马上返回0,但是又衍生出一个问题,因为读取到档案结尾时所回传的也是0,这样无法得知是哪中情况;而O_NONBLOCK它在读取不到数据时会回传-1,并且设置errno为EAGAIN。

select函数读写

int select(int nfds, fd_set *rdfds, fd_set *wtfds, fd_set *exfds, struct timeval *timeout)
  • ndfs:select监视的文件句柄,一般设为要监视的文件中的最大文件号加一;
  • rdfds:select监视的可读文件句柄集合,当rdfds映象的文件句柄状态变成可读时系统告诉select函数返回。这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值,可以传入NULL值,表示不关心任何文件的读变化;
  • wtfds: select监视的可写文件句柄集合,当wtfds映象的文件句柄状态变成可写时系统告诉select函数返回,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值,可以传入NULL值,表示不关心任何文件的写变化;
  • exfds:select监视的异常文件句柄集合,当exfds映象的文件句柄上有特殊情况发生时系统会告诉select函数返回;
  • timeout:select的超时结束时间,设为0则为阻塞模式,设为大于0的值时若所监视的句柄无状态变化则等待timeout时间后返回0;

配置函数:

  • FD_ZERO(fd_set *fdset):清空fdset与所有文件句柄的联系。
  • FD_SET(int fd, fd_set *fdset):建立文件句柄fd与fdset的联系。
  • FD_CLR(int fd, fd_set *fdset):清除文件句柄fd与fdset的联系。
  • FD_ISSET(int fd, fdset *fdset):检查fdset联系的文件句柄fd是否可读写,>0表示可读写。

select函数非常强大,它能同时监测多个对象,只要在注册的对象集中有一个或多个对象被激活就会有反应,所以利用select函数能在一个线程中处理多个等待式操作,这里以多串口阻塞读取为例:

#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
 
#define USAR1  "/dev/ttyS1"
#define USAR2  "/dev/ttyS2"
#define USAR3  "/dev/ttyS3"
#define USAR4  "/dev/ttyS4"
char buf[255] = {0};
 
int set_port_attr (int fd,int  baudrate, int  databit, const char *stopbit, char parity, int vtime,int vmin );
static void set_baudrate (struct termios *opt, unsigned int baudrate);
static void set_data_bit (struct termios *opt, unsigned int databit);
static void set_stopbit (struct termios *opt, const char *stopbit);
static void set_parity (struct termios *opt, char parity);
 
void main()
{
    int fd1,fd2,fd3,fd4;
    int ret;
    int rxlen = 0;
    fd_set rfds;
    struct timeval tv;
    int retval;
 
    fd1 = open(USAR1, O_RDWR | O_NOCTTY );//阻塞式读写             非阻塞| O_NDELAY | O_NONBLOCK
    if (fd1 < 0) 
    {
      perror("open uart1 error\n");
    }
    fd2 = open(USAR2, O_RDWR | O_NOCTTY );//阻塞式读写             非阻塞| O_NDELAY | O_NONBLOCK
    if (fd2 < 0) 
    {
      perror("open uart2 error\n");
    }
    fd3 = open(USAR3, O_RDWR | O_NOCTTY );//阻塞式读写             非阻塞| O_NDELAY | O_NONBLOCK
    if (fd3 < 0) 
    {
      perror("open uart3 error\n");
    }
    fd4 = open(USAR4, O_RDWR | O_NOCTTY );//阻塞式读写             非阻塞| O_NDELAY | O_NONBLOCK
    if (fd4 < 0) 
    {
      perror("open uart4 error\n");
    }
    ret = set_port_attr(fd1, B115200, 8, "1", 'N',1,255 );    /* 115200 8n1      */
    if(ret < 0) 
    {
      printf("set uart1 arrt faile \n");
      exit(-1);
    }
    ret = set_port_attr(fd2, B115200, 8, "1", 'N',1,255 );    /* 115200 8n1      */
    if(ret < 0) 
    {
      printf("set uart2 arrt faile \n");
      exit(-1);
    }
    ret = set_port_attr(fd3, B115200, 8, "1", 'N',1,255 );    /* 115200 8n1      */
    if(ret < 0) 
    {
      printf("set uart3 arrt faile \n");
      exit(-1);
    }
    ret = set_port_attr(fd4, B115200, 8, "1", 'N',1,255 );    /* 115200 8n1      */
    if(ret < 0) 
    {
      printf("set uart4 arrt faile \n");
      exit(-1);
    }
    while(1)
    {
       FD_ZERO(&rfds);
       FD_SET(fd1, &rfds);
       FD_SET(fd2, &rfds);
       FD_SET(fd3, &rfds);
       FD_SET(fd4, &rfds);
    //   tv.tv_sec = 1;                           //in block mode is not used
    //   tv.tv_usec = 0;
       ret = select(fd4 + 1, &rfds, NULL, NULL, NULL);  //block mode
       if(ret > 0)
       {
           if(FD_ISSET(fd1,&rfds))
           {
               rxlen = read(fd1, buf, 255);
               if(rxlen > 0)
               {
                 printf("len = %d\n\r",rxlen);
                 printf("rx:%s\n\r",buf);
                 write(fd1, buf, rxlen);
               }
           }
           if(FD_ISSET(fd2,&rfds))
           {
               rxlen = read(fd2, buf, 255);
               if(rxlen > 0)
               {
                 printf("len = %d\n\r",rxlen);
                 printf("rx:%s\n\r",buf);
                 write(fd2, buf, rxlen);
               }
           }
           if(FD_ISSET(fd3,&rfds))
           {
               rxlen = read(fd3, buf, 255);
               if(rxlen > 0)
               {
                 printf("len = %d\n\r",rxlen);
                 printf("rx:%s\n\r",buf);
                 write(fd3, buf, rxlen);
               }
           }
           if(FD_ISSET(fd4,&rfds))  
           {
               rxlen = read(fd4, buf, 255);
               if(rxlen > 0)
               {
                 printf("len = %d\n\r",rxlen);
                 printf("rx:%s\n\r",buf);
                 write(fd4, buf, rxlen);
               }
           }
       }     
    }
}

此段程序为同时监控4路串口接收状态,将接收的内容直接原路返回,串口采用的是阻塞读取模式,select函数也采用阻塞式读取模式。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/117308.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【05】概率图表示之马尔可夫随机场

概率图表示之马尔可夫随机场 文章目录马尔可夫随机场正式定义与贝叶斯网络的比较马尔可夫随机场中的独立性条件随机场示例正式定义示例&#xff08;续&#xff09;CRF特性因子图贝叶斯网络可以以一种紧凑的方式表示许多概率分布。然而&#xff0c;我们在前一章中已经看到&…

笔试强训(8)

笔试题1:密码强度等级密码强度等级_牛客题霸_牛客网 在这个题中: 1)统计密码的长度直接通过length()来进行解决 2)统计大写字母和小写字母的个数分别在函数里面定义两个变量来进行解决 3)统计数字和富豪也是分别用两个变量来进行保存 import java.util.Scanner;// 注意类名必须…

记一次 Maven 打包后,第三方无法使用的排查记录

你好&#xff0c;我是悟空。 本文主要内容如下&#xff1a; 前言 最近遇到一个需求&#xff1a; 写一个工具类的 JAR 包&#xff0c;然后提供给第三方使用。 期间遇到了一些问题&#xff1a; 第三方引入 JAR 包后&#xff0c;无法 import。第三方引入 JAR 包后&#xff0c…

你可以不看世界杯,但你一定要知道这些

2022卡塔尔世界杯&#xff0c;阿根廷夺冠&#xff0c;举世沸腾。 ​夺冠之路&#xff0c;遍布荆棘 时隔36年&#xff0c;阿根廷再次夺得大力神杯&#xff0c;回望夺冠之路&#xff0c;坎坷遍布&#xff0c;荆棘丛生。 2006年夏天&#xff0c;梅西第一次参加世界杯。时任阿根廷…

Mybatis源码(一)获取数据源

前言 Mybatis做为一种半ORM框架&#xff08;半&#xff1a;需要手动写sql&#xff09;。ORM&#xff08;Object Relational Mapping&#xff09;的技术本质是&#xff1a;ORM框架将对象的值 映射到 对应数据库类型&#xff1a; 如 String -> varchar。 且mybatis分为两种实…

数字孪生核电站促进界面监测的应用实践

未来核电站将向着数字化、智能化发展,“少人值守、智能监测”会广泛应用于核电站运行管理。利用数字孪生技术,可以对实体核电站和孪生核电站的数据进行交换分析,促进核电站的运行管理和监测,更好地确保反应堆运行安全。 数字孪生核电站促进界面监测的应用实践 北京智汇云舟科技…

h5中使用微信分享

1.需要 绑定域名&#xff1a; 先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”&#xff08;即访问前端项目对应的域名)。 2.在项目中引入sdk: 在需要调用 JS 接口的页面引入如下 JS 文件&#xff0c;&#xff08;支持https&#xff09;&#xff…

搭vue项目(初级版)

这个项目只有 会员管理和直播管理两个模块。创建两个模块是为了验证一下路由跳转。 下载项目&#xff1a; 可以到我的资源中下载压缩包 或者 git clone 前端项目搭建: 前端搭建的项目&#xff0c;仅供学习使用 1.安装vue-cli,全局只需要安装一次&#xff0c;如果安装过一次&am…

MyBatisPlus ---- 入门案例

MyBatisPlus ---- 入门案例1. 开发环境2. 创建数据库及表a>创建表b>添加数据3. 创建SpringBoot工程a>初始化工程b>引入依赖c>idea中安装lombok插件4. 编写代码a>配置application.ymlb>启动类c>添加实体d>添加mappere>测试f>添加日志1. 开发环…

了解 Oracle 中单引号与双引号的用法,一篇文章教会你!

无论测试或者开发&#xff0c;对数据库的增删改查都是家常便饭。但有些小知识是经常被忽略&#xff0c;却又不能不去了解的&#xff0c;例如单引号和双引号的用法和区别&#xff0c;看完这一篇&#xff0c;你肯定会有收获。 首先我们要区别一个概念&#xff0c;即单引号(‘)和双…

docker应用部署示例

Docker 应用部署 一、部署MySQL 搜索mysql镜像 docker search mysql拉取mysql镜像 docker pull mysql:5.6创建容器&#xff0c;设置端口映射、目录映射 # 在/root目录下创建mysql目录用于存储mysql数据信息 mkdir ~/mysql cd ~/mysqldocker run -id \ -p 3307:3306 \ --na…

如何通过文档管理控制合同管理

如何通过文档管理控制合同管理 如果您的公司处理的合同比以往任何时候都多&#xff0c;那么您并不孤单。这种指数级增长的原因包括日益增长的监管要求、供应链问题以及全球化带来的业务关系的复杂性。此外&#xff0c;员工更频繁地换工作&#xff0c;因此&#xff0c;需要管理更…

Unity实用小工具—以对象形式操作Sqlite

一、介绍 1.1、版本说明&#xff1a;使用的Unity版本为个人版2020.3.39&#xff0c;数据库为Sqlite&#xff08;一个轻量级跨平台数据库&#xff09;&#xff0c;Sqlite的查看管理工具可以在网上下载https://dbeaver.io/download/&#xff0c;可以直接保存下来使用。 1.2、数…

微服务(四)——统一网关

目录1. 概念2. 实现网关1. 实现流程2. 小结3. 断言工厂4. 过滤器工厂1. GatewayFilter2. GlobalFilter3. 过滤器的执行顺序5. 解决跨域问题1. 概念 网关的作用&#xff1a; 认证、鉴权服务路由、负载均衡请求限流 网关的实现&#xff1a; gateway 基于Spring5中提供的WebFlu…

linux 设置登录提示语

勿以恶小而为之&#xff0c;勿以善小而不为---- 刘备 /etc/motd 文件里面 保存的是 登录后提示语 vim /etc/motd可以放置自定义的 文字信息 -------------------- 每天都要加油努力噢&#xff0c;岳泽霖!!! -------------------登录之后&#xff0c;就会展示信息: 参考链接: …

【Linux】Linux命令行git的使用

前进才是唯一的方向 文章目录一、git是什么&#xff1f;二、gitee仓库创建1.新建仓库2.复制仓库链接3.克隆远端仓库到本地来三、git提交代码1.下载git2. 配置用户名和邮箱&#xff08;否则git commit无法正常使用&#xff09;3. git提交代码三板斧3.1 git add&#xff08;将代…

git merge合并开发分支到上线分支遇到的问题,提示 no new changes

git merge 后 push 到 Gerrit 失败&#xff0c;提示 no new changes 解决思路&#xff1a; 分析&#xff1a;no new changes 的意思&#xff0c;是说&#xff0c;这个合并&#xff0c;是个线性的合并。而合并的那些历史的 commit 节点&#xff0c;在 gerrit 上都已经评审过了&…

在Linux中安装ShowDoc

在Linux中&#xff0c;有两种方式安装ShowDoc。第一种是自动脚本安装&#xff0c;第二种是手动安装。官方推荐使用自动脚本安装ShowDoc。如果自动脚本安装ShowDoc失败&#xff0c;可以考虑手动安装ShowDoc。 自动脚本安装ShowDoc 自动脚本利用docker来安装运行环境&#xff0…

酒鬼私定,只是酒鬼酒一次破圈营销?

围坐红泥小火炉&#xff0c;煮酒谈今夕。 过去一年多时间&#xff0c;经历了业绩向上&#xff0c;股市向下的反差时期后&#xff0c;越来越多人意识到白酒行业已步入存量时代。 2022年前三季度&#xff0c;中国规模以上白酒行业实现总产量487.9万千升&#xff0c;同比减少2.5…

proxychains for Windows

proxychains for Windows背景介绍项目地址使用scoop安装proxychains for windows验证命令行能否调用proxychains配置代理使用为Windows终端配置proxy--适用于cmd为Windows终端配置proxy--适用于PowerShellpowershell配置变量背景介绍 有时候Windows下的一些命令行程序想要挂代…