Linux下Socket连接超时的一种实现方法

Linux下Socket连接超时的一种实现方法


天新网 【转载】 2009年03月24日 18:50
目前各平台通用的设置套接字(Socket)连接超时的办法是:
  1. 创建套接字,将其设置成非阻塞状态。
  2. 调用connect连接对端主机,如果失败,判断当时的errno是否为EINPROGRESS,也就是说是不是连接正在进行中,如果是,转到步骤3,如果不是,返回错误。
  3. 用select在指定的超时时间内监听套接字的写就绪事件,如果select有监听到,证明连接成功,否则连接失败。
  以下是Linux环境下的示例代码:



#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <time.h>

int main(int argc, char *argv[])
{
        int fd, retval;
        struct sockaddr_in addr;
        struct timeval timeo = {3, 0};
        socklen_t len = sizeof(timeo);
        fd_set set;

        fd = socket(AF_INET, SOCK_STREAM, 0);
        if (argc == 4)
                timeo.tv_sec = atoi(argv[3]);
        fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(argv[1]);
        addr.sin_port = htons(atoi(argv[2]));
        printf("%dn", time(NULL));
        if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
                printf("connectedn");
                return 0;
        }
        if (errno != EINPROGRESS) {
                perror("connect");
                return -1;
        }
        FD_ZERO(&set);
        FD_SET(fd, &set);
        retval = select(fd + 1, NULL, &set, NULL, &timeo);
        if (retval == -1) {
                perror("select");
                return -1;
        } else if(retval == 0) {
                fprintf(stderr, "timeoutn");
                printf("%dn", time(NULL));
                return 0;
        }
        printf("connectedn");

        return 0;
}


  实际运行结果如下:

xiaosuo@gentux perl \$ ./a.out 10.16.101.1 90
1180289276
timeout
1180289279
xiaosuo@gentux perl \$ ./a.out 10.16.101.1 90 1
1180289281
timeout
1180289282

  可以看到,以上代码工作的很好,并且如果你想知道连接发生错误时的确切信息的话,你可以用getsocketopt获得:

int error;
socklen_t errorlen = sizeof(error);

getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &errorlen);


  但是多少有些复杂,如果有象SO_SNDTIMO/SO_RCVTIMO一样的套接字参数可以让超时操作跳过select的话,世界将变得更美好。当然你还可以选用象apr一样提供了简单接口的库,但我这里要提的是另一种方法。

  呵呵,引子似乎太长了点儿。读Linux内核源码的时候偶然发现其connect的超时参数竟然和用SO_SNDTIMO操作的参数一致:

  File: net/ipv4/af_inet.c

   559      timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
   560
   561      if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
   562          /* Error code is set above */
   563          if (!timeo || !inet_wait_for_connect(sk, timeo))
   564              goto out;
   565
   566          err = sock_intr_errno(timeo);
   567          if (signal_pending(current))
   568              goto out;
   569      }

  这意味着: 在Linux平台下,可以通过在connect之前设置SO_SNDTIMO来达到控制连接超时的目的。简单的写了份测试代码:


#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

int main(int argc, char *argv[])
{
        int fd;
        struct sockaddr_in addr;
        struct timeval timeo = {3, 0};
        socklen_t len = sizeof(timeo);

        fd = socket(AF_INET, SOCK_STREAM, 0);
        if (argc == 4)
                timeo.tv_sec = atoi(argv[3]);
        setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len);
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(argv[1]);
        addr.sin_port = htons(atoi(argv[2]));
        if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
                if (errno == EINPROGRESS) {
                        fprintf(stderr, "timeoutn");
                        return -1;
                }
                perror("connect");
                return 0;
        }
        printf("connectedn");

        return 0;
}


  执行结果:

xiaosuo@gentux perl \$ ./a.out 10.16.101.1 90
1180290583
timeout
1180290586
xiaosuo@gentux perl \$ ./a.out 10.16.101.1 90 2
1180290590
timeout
1180290592

  和设想完全一致!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux网络编程之TCP/IP基础篇 01TCPIP基础(一) ISO/OSI参考模型 TCP/IP四层模型 基本概念(对等通信、封装、分用、端口) 02TCPIP基础(二) 最大传输单元(MTU)/路径MTU 以太网帧格式 ICMP ARP RARP 03TCPIP基础(三) IP数据报格式 网际校验和 路由 04TCPIP基础(四) TCP特点 TCP报文格式 连接建立三次握手 连接终止四次握手 TCP如何保证可靠性 05TCPIP基础(五) 滑动窗口协议 UDP特点 UDP报文格式 Linux网络编程之socket编程篇 06socket编程(一) 什么是socket IPv4套接口地址结构 网络字节序 字节序转换函数 地址转换函数 套接字类型 07socket编程(二) TCP客户/服务器模型 回射客户/服务器 socket、bind、listen、accept、connect 08socket编程(三) SO_REUSEADDR 处理多客户连接(process-per-conection) 点对点聊天程序实现 09socket编程(四) 流协议与粘包 粘包产生的原因 粘包处理方案 readn writen 回射客户/服务器 10socket编程(五) read、write与recv、send readline实现 用readline实现回射客户/服务器 getsockname、getpeername gethostname、gethostbyname、gethostbyaddr 11socket编程(六) TCP回射客户/服务器 TCP是个流协议 僵进程与SIGCHLD信号 12socket编程(七) TCP 11种状态 连接建立三次握手、连接终止四次握手 TIME_WAIT与SO_REUSEADDR SIGPIPE 13socket编程(八) 五种I/O模型 select 用select改进回射客户端程序 14socket编程(九) select 读、写、异常事件发生条件 用select改进回射服务器程序。 15socket编程(十) 用select改进第八章点对点聊天程序 16socket编程(十一) 套接字I/O超时设置方法 用select实现超时 read_timeout函数封装 write_timeout函数封装 accept_timeout函数封装 connect_timeout函数封装 17socket编程(十二) select限制 poll 18socket编程(十三) epoll使用 epoll与select、poll区别 epoll LT/ET模式 19socket编程(十四) UDP特点 UDP客户/服务基本模型 UDP回射客户/服务器 UDP注意点 20socket编程(十五) udp聊天室实现 21socket编程(十六) UNIX域协议特点 UNIX域地址结构 UNIX域字节流回射客户/服务 UNIX域套接字编程注意点 22socket编程(十七) socketpair sendmsg/recvmsg UNIX域套接字传递描述符字 Linux网络编程之进程间通信篇 23进程间通信介绍(一) 进程同步与进程互斥 进程间通信目的 进程间通信发展 进程间通信分类 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) 消息队列 IPC对象数据结构 消息队列结构 消息队列在内核中的表示 消息队列函数 26System V消息队列(二) msgsnd函数 msgrcv函数 27System V消息队列(三) 消息队列实现回射客户/服务器 28共享内存介绍 共享内存 共享内存示意图 管道、消息队列与共享内存传递数据对比 mmap函数 munmap函数 msync函数 29System V共享内存 共享内存数据结构 共享内存函数 共享内存示例 30System V信号量(一) 信号量 信号量集结构 信号量集函数 信号量示例 31System V信号量(二) 用信号量实现进程互斥示例 32System V信号量(三) 用信号集解决哲学家就餐问题 33System V共享内存与信号量综合 用信号量解决生产者消费者问题 实现shmfifo 34POSIX消息队列 POSIX消息队列相关函数 POSIX消息队列示例 35POSIX共享内存 POSIX共享内存相关函数 POSIX共享内存示例 Linux网络编程之线程篇 36线程介绍 什么是线程 进程与线程 线程优缺点 线程模型 N:1用户线程模型 1:1核心线程模型 N:M混合线程模型 37POSIX线程(一) POSIX线程库相关函数 用线程实现回射客户/服务器 38POSIX线程(二) 线程属性 线程特定数据 39POSIX信号量与互斥锁 POSIX信号量相关函数 POSIX互斥锁相关函数 生产者消费者问题 自旋锁与读写锁介绍 40POSIX条件变量 条件变量 条件变量函数 条件变量使用规范 使用条件变量解决生产者消费者问题 41一个简单的线程池实现 线程池性能分析 线程池实现
20.1 ftp服务 ftp采用客户/服务器工作模式,这里采用的是vsftpd ftp服务器软件。ftp工作方式分为两种,一种port主动模式,一种pasv被动模式,是服务主动与被动进行连接。一般ftp服务器都为被动模式 。 20.1.1 vsftp概述 rpm -qc vsftpd /etc/logrotate.d/vsftpd.log /etc/pam.d/vsftpd /*vsftp的安全验证文件*/ /etc/vsftpd/ftpusers /*其中的用户不能登陆ftp*/ /etc/vsftpd/user_list /*其中的用户不能登陆ftp同上一样*/ /etc/vsftpd/vsftpd.conf /*ftp主配置文件*/ /etc/vsftpd/vsftpd_conf_migrate.sh vsftp的主目录的位置在/var/ftp下,并且是系统默认,不能更改。vsftp在通过rpm包安装好后,打开其服务并设为自动运行后,ftp就可以 提供服务了。 20.1.2 vsftp安装与启动 如果没有安装的话,通过以下方式进行安装。 rpm -ivh vsftpd-2.0.4-1.2.i386.rpm warning: vsftpd-2.0.4-1.2.i386.rpm: Header V3 DSA signature: NOKEY, key ID 4f2a6fd2 Preparing... ########################################### [100%] 1:vsftpd ########################################### [100%] vsftpd服务采用是独立启动方式来启动的。 chkconfig --level 345 vsftpd on设为开机自启动 service vsftpd start 启动ftp服务。 20.2 vsftp访问配置 20.2.1 vsftp匿名用户 匿名用户:ftp 与anonymous其主目录为/var/ftp 普通用户:用户名为登录用户名,主目录为/home/用户名 20.2.2 vsftp默认配置文件 去掉#后配置选项如下: vi vsftpd.conf anonymous_enable=YES /*匿名用户启用*/ local_enable=YES /*本地用户可登陆*/ write_enable=YES /*是否允许写*/ local_umask=022 /*锁定创建文件权限*/ #anon_upload_enable=YES /*是否允许匿名用户上传*/ #anon_mkdir_write_enable=YES /*是否允许匿名用户创建目录*/ dirmessage_enable=YES /*允许显示目录信息*/ xferlog_enable=YES /*启用记录上传与下载日志*/ connect_from_port_20=YES /*开启20端口*/ #chown_uploads=YES #chown_username=whoever #xferlog_file=/var/log/vsftpd.log /*上传与下载日志文件*/ xferlog_std_format=YES /*使用标准日志格式*/ #idle_session_timeout=600 /*会话空闲时间*/ #data_connection_timeout=120 /*连接超时时间*/ #nopriv_user=ftpsecure #async_abor_enable=YES #ascii_upload_enable=YES /*是否使用ascii格式上传*/ #ascii_download_enable=YES /*是否使用ascii格式下载*/ #ftpd_banner=Welcome to blah FTP service. /*服务器banner*/ #deny_email_enable=YES /*启用电子邮件阻止*/ #banned_email_file=/etc/vsftpd/banned_emails /* 阻止的邮件地址文件*/ #chroot_list_enable=YES /*是否允许用户改变主目录*/ #chroot_list_file=/etc/vsftpd/chroot_list /*允许改变主目录的用户*/ #ls_recurse_enable=YES /*是否允许用户ls -R循环显示每一个目录*/ pam_service_name=vsftpd /*验证服务名*/ userlist_enable=YES /*用户列表中的用户不能登录FTP*/ #userlist_file=/etc/vsftpd/user_list listen=YES /*监听模式*/ tcp_wrappers=YES 说明:默认配置文件就已经能够实现匿名用户对/var/ftp文件内容的下载,以及本机用户对自已主目录的访问(上传与下载)。 20.3 vsftp配置基本实例 20.3.1 改变端口号 vi vsftpd.conf #新增底下一行,原有的配置不动 listen_port=2121 #重启服务 service vsftpd restart 20.3.2 特定用户不能更改目录 使用者的预设目录为/home/username,若是我们不希望使用者redhat在ftp 时能够切换到上一层目录/home,则可参考以下步骤。 #去掉注释 chroot_list_enable=YES chroot_list_file=/etc/vsftpd/chroot_list #或以上选项注释掉,所有用户都不能更改目录。 #编辑下列文件 vi /etc/vsftpd/chroot_list #加入内容 redhat #重启服务 service vsftpd restart 20.3.3 允许匿名上传 vi vsftpd.conf #修改以下内容 anon_upload_enable=YES /*是否允许匿名用户上传*/ anon_mkdir_write_enable=YES /*是否允许匿名用户创建目录*/ #重启服务 service vsftpd restart 注意:对于上传目录,必须设为可写才行。 chmod o+w /var/ftp 20.3.4 取消匿名登录 说明:取消匿名登录后,系统用户都可以通过用户名与密码来访问FTP服务器了。 vi vsftpd.conf #修改以下内容 anonymous_enable=NO #重启服务 service vsftpd restart 20.3.5 设置欢迎信息 vi vsftpd.conf #修改以下内容 ftpd_banner=Welcome to koumm’s FTP service. /*服务器欢迎信息*/ dirmessage_enable=YES /*默认是开启状态*/ #然后在/var/ftp中建立.message文件。 #该文件为目录说明文件,用于对目录的说明,每个目录中都可有。 vi /var/ftp/.message 欢迎访问ftp主目录。 /*通过SecureCRT登录可以打汉字,并可显示*/ #重启服务 service vsftpd restart 20.3.6 以独立进程联机 vi vsftpd.conf #新加入以下内容 setproctitle_enable=YES /*默认是开启状态*/ #重启服务 service vsftpd restart #测试 ps -ef|grep ftp #该功能可能只是在管理上可以查看用户登录的情况吧。 20.3.7 限制下载速度 vi vsftpd.conf #新加入以下内容 anon_max_rate=100000 /*匿名最高速为100KB*/ local_max_rate=200000 /*本机用户最高速为200KB */ #实际速度会在80-120%之间。 #重启服务 service vsftpd restart 20.3.8 使用pasv联机模式 vi vsftpd.conf #新加入以下内容 listen_port=2121 /*监听2121端口,用于防火墙 */ pasv_enable=YES /*启用pasv模式*/ pasv_min_port=9981 /*pasv端口范围*/ pasv_max_port=9986 #重启服务 service vsftpd restart 20.3.9 超级守护程序启动 vi vsftpd.conf #修改以下内容 listen=NO /*监听2121端口,用于防火墙 */ #在/etc/xinetd.d/新建以下内容 vi /etc/xinetd.d/vsftpd service vsftpd { disable = no socket_type = stream wait = no user = root server = /usr/sbin/vsftpd port = 21 log_on_success += PID HOST DURATION log_on_failure += HOST } #重启服务 service xinetd restart 注:该配置是对以前服务的一个加深的理解,也相应的也提供了一个处理问题的思路。 20.3.10 最大连机数 vi vsftpd.conf #加入以下内容 max_clients = 100 /*服务器最大连机默认为0无限制*/ max_per_ip = 5 /*单IP最大连机默认为0无限制*/ #重启服务 service xinetd restart 注:该配置是对以前服务的一个加深的理解,也相应的也提供了一个处理问题的思路。 20.3.11 特定用户不能登录方法一 #其中的用户不能登陆ftp /etc/vsftpd/ftpusers #可以通过以下文件来进行控制的,第二行内容。 vi /etc/pam.d/vsftpd #%PAM-1.0 auth required pam_listfile.so item=user sense=deny file= /etc/vsftpd/ftpusers onerr=succeed auth required pam_shells.so auth include system-auth account include system-auth session include system-auth session required pam_loginuid.so #如果把上面的sense=deny改为allow后,也就是说只有/etc/vsftpd/ftpusers中的用户才能够访问ftp服务器了。这里提供了一个配置思路, 以供在实际环境中使用。 20.3.12 特定用户不能登录方法二 #编辑下列文件 vi /etc/vsftpd/chroot_list #修改或加入内容user_list文件本身就有,如没有,请手动添加。 # userlist_enable=YES userlist_file=/etc/vsftpd/ user_list #重启服务 service vsftpd restart 20.4 ftp虚拟用户配置 虚拟帐户与samba中的虚拟帐户有点像,就是为了防止别人用真正的帐户登录系统,而采用的一个帐户的别名帐户,而虚拟帐户只能够登录 ftp,而不能用做其它目的。 20.4.1 创建虚拟帐户文件 [root@redhat vsftpd]# vi vuser.txt bill /*用户名*/ password /*密码*/ koumm abc,.123 通过以上文件来创建用户数据库。 20.4.2 创建虚拟帐户数据库文件 [root@redhat vsftpd]# db_load -T -t hash -f vuser.txt /etc/vsftpd_login.db [root@redhat vsftpd]# chmod 600 /etc/vsftpd_login.db [root@redhat vsftpd]# ll /etc/vsftpd_login.db -rw------- 1 root root 12288 6月 15 17:06 /etc/vsftpd_login.db 修改权限以保证安全。 20.4.3 配置pam文件 为了能够使用ftp服务器能够使用数据库文件对用户进行身份验证,还需要修改vsftpd的PAM文件,把以前的pam中的内容注释掉,并加入以下 内容。 [root@redhat etc]# vi /etc/pam.d/vsftpd #auth required pam_listfile.so item=user sense=deny file=/etc/vsftpd.ftpusers onerr=succeed #auth required pam_stack.so service=system-auth #auth required pam_shells.so #account required pam_stack.so service=system-auth #session required pam_stack.so service=system-auth auth required pam_userdb.so db=/etc/vsftpd_login account required pam_userdb.so db=/etc/vsftpd_login 20.4.4 创建虚拟帐户目录 mkdir /var/ftp/vuser useradd -d /var/ftp/vuser vuser useradd ftpvip 说明:创建一个帐户,指定主目录,也是ftp的主目录。不指定就是/home/vuser chown vuser.vuser /var/ftp/vuser chmod o+rw /var/ftp/vuser 20.4.5 编辑配置文件 1.编辑配置文件 [root@redhat pam.d]# vi /etc/vsftpd/vsftpd.conf anonymous_enable=NO /*不能允许匿名用户登录*/ local_enable=YES /*本地用户登录*/ write_enable=NO local_umask=022 anon_upload_enable=NO anon_mkdir_write_enable=NO #加入以下内容 guest_enable=YES /*开启虚拟帐户访问*/ guest_username=vuser /*虚拟帐户对应的系统帐户*/ 说明:虚拟用户的上传下载权限的配置是用匿名配置选项来进行配置的,前提是不能允许匿名用户登录,可以匿名用户可写,虚拟用户就可 以写或上传了。 2.编辑独立配置文件 (1)虚拟帐户配置文件目录 vsftpd可以为不同的虚拟用户创建不同的单独的配置文件,来实现不同的功能,思想就是:可以为不同的虚拟用户对应不同的实体用户,从 而实现不能的功能。 [root@redhat pam.d]# vi /etc/vsftpd/vsftpd.conf 加入以下内容: vi /etc/vsftpd/vsftpd.conf user_config_dir=/ftpconfig /*虚拟用户主配置文件目录*/ (2)单独创建虚拟帐户配置文件 vi /ftpconfig/bill /*创建的虚拟用户*/ guest_enable=yes guest_username=vuser /*设置ftp对应的系统帐号为ftpuser*/ anon_world_readable_only=no /*允许匿名用户浏览文件系统*/ anon_max_rate=50000 /*限定传输速率为50KB/s*/ vi /ftpconfig/koumm /*创建的虚拟用户*/ guest_enable=yes /*开启虚拟帐号登录*/ guest_username=ftpvip /*设置ftp对应的系统帐号为ftpvip*/ anon_world_readable_only=no /*允许匿名用户浏览器整个服务器的文件系统*/ write_enable=yes /*允许在文件系统写入权限*/ anon_mkdir_write_enable=yes /*允许创建文件夹 */ anon_upload_enable=yes /*开启匿名帐号的上传功能*/ anon_max_rate=100000 /*限定传输速度为100KB/s*/ 说明:以上实体用户还需要事先创建,用户的主目录如是事先安装的话在/home中。以上方法可以应用一些复杂的应用环境中。 20.5 ftp客户端 20.5.1 ftp命令 ftp命令的功能是在本地机和远程机之间传送文件。 该命令的一般格式如下: ftp 主机名/IP 最常用的命令有: ls 列出远程机的当前目录 cd 在远程机上改变工作目录 lcd 在本地机上改变工作目录 ascii 设置文件传输方式为ASCII模式 binary 设置文件传输方式为二进制模式 close 终止当前的ftp会话 hash 每次传输完数据缓冲区中的数据后就显示一个#号 get(mget) 从远程机传送指定文件到本地机 put(mput) 从本地机传送指定文件到远程机 open 连接远程ftp站点 quit 断开与远程机的连接并退出ftp ? 显示本地帮助信息
Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。可是使用Select就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。下面详细介绍一下! Select的函数格式(我所说的是Unix系统下的伯克利socket编程,和windows下的有区别,一会儿说明): int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout); 先说明两个结构体: 第一,struct fd_set可以理解为一个集合,这个集合中存放的是文件描述符(file descriptor),即文件句柄,这可以是我们所说的普通意义的文件,当然Unix下任何设备、管道、FIFO等都是文件形式,全部包括在内,所以毫无疑问一个socket就是一个文件,socket句柄就是一个文件描述符。fd_set集合可以通过一些宏由人为来操作,比如清空集合FD_ZERO(fd_set *),将一个给定的文件描述符加入集合之中FD_SET(int ,fd_set *),将一个给定的文件描述符从集合中删除FD_CLR(int ,fd_set*),检查集合中指定的文件描述符是否可以读写FD_ISSET(int ,fd_set* )。一会儿举例说明。 第二,struct timeval是一个大家常用的结构,用来代表时间值,有两个成员,一个是秒数,另一个是毫秒数。 具体解释select的参数: int maxfdp是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,不能错!在Windows中这个参数的值无所谓,可以设置不正确。 fd_set *readfds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。 fd_set *writefds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。 fd_set *errorfds同上面两个参数的意图,用来监视文件错误异常。 struct timeval* timeout是select的超时时间,这个参数至关重要,它可以使select处于三种状态,第一,若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;第三,timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。 返回值: 负值:select错误 正值:某些文件可读写或出错 0:等待超时,没有可读写或错误的文件
### 回答1: 在Linux操作系统下,可以使用SocketCAN来进行CAN总线通信。SocketCAN是一个通用的CAN设备驱动和套接字接口,它提供了一种基于套接字的API来访问CAN设备。 首先,需要确保系统内核中加载了CAN设备驱动。可以通过modprobe命令来加载对应的内核模块。例如,对于CAN设备驱动“can0”,可以使用以下命令加载该模块: ``` sudo modprobe can sudo modprobe can_raw sudo modprobe vcan ``` 接下来,需要创建一个CAN设备接口,在这个接口上进行通信。可以使用以下命令创建一个CAN设备接口: ``` sudo ip link set can0 type can bitrate 250000 sudo ifconfig can0 up ``` 上述命令中的“can0”为设备接口名称,可以根据需要自行指定。而“bitrate 250000”设置了CAN总线的波特率为250kbps,也可以根据实际需求调整波特率。 在CAN设备接口创建成功后,就可以使用SocketCAN来进行CAN总线通信了。可以使用C语言或者其他编程语言进行开发。 在C语言中,可以使用socket函数创建一个套接字,并调用相应的API函数来发送和接收CAN消息。具体的代码实现可以参考SocketCAN的官方文档和示例代码。 总之,通过使用SocketCAN,可以很方便地在Linux系统下进行CAN总线通信,实现CAN消息的发送和接收。同时,可以根据实际需求进行定制开发,以满足特定的应用场景。 ### 回答2: 在Linux下,使用SocketCAN可以进行CAN总线通信。SocketCAN是Linux内核中的一种CAN总线子系统,它提供了一组API函数,使开发者可以通过套接字接口访问CAN总线。 首先,在使用SocketCAN之前,需要确保Linux内核已经加载了can和can-raw的驱动模块。可以通过执行命令`sudo modprobe can`和`sudo modprobe can-raw`加载这两个模块。 接下来,可以使用`socket()`函数创建一个套接字,并使用`bind()`函数将该套接字与CAN总线上的某个接口进行绑定。例如,可以使用`AF_CAN`作为地址族参数,使用`struct sockaddr_can`结构体来指定CAN接口的名称和其他参数。然后,使用`recvfrom()`函数从套接字中接收CAN帧数据,使用`sendto()`函数将CAN帧数据发送到套接字。在`recvfrom()`和`sendto()`函数的参数中,需要使用`struct can_frame`结构体来描述CAN帧的数据。 除了基本的接收和发送功能外,SocketCAN还提供了一些其他的功能,比如设置过滤器来屏蔽或接收特定ID的CAN帧,以及设置CAN总线的位速率等。这些功能可以通过使用`setsockopt()`函数,并指定`SOL_CAN_RAW`或`SOL_CAN_FILTER`等选项来实现。 总之,使用SocketCAN可以方便地在Linux实现CAN总线通信。通过使用SocketCAN提供的API函数和结构体,开发者可以在Linux系统中直接使用套接字接口进行CAN数据的接收和发送,同时也可以利用SocketCAN提供的其他功能来优化CAN总线通信的处理。 ### 回答3: SocketCAN是一个开源的Linux内核网络层协议栈,它提供了一种统一的接口,用于在Linux中进行CAN总线通信。它能够实现CAN硬件的底层访问和CAN消息的发送和接收,提供了一些有用的工具和库,方便开发人员进行CAN总线应用程序的开发。 在Linux中使用SocketCAN进行CAN总线通信,首先需要加载CAN网络驱动模块。然后,可以使用工具如candump和cansend来发送和接收CAN消息。candump用于监听CAN总线上的消息,而cansend用于发送CAN消息。 另外,SocketCAN还提供了一组C语言库函数,可以用于在程序中进行CAN总线通信。这些库函数可以方便地创建和绑定CAN套接字,发送和接收CAN消息。通过设置套接字的选项,还可以实现CAN过滤和接收超时等功能。 使用SocketCAN进行CAN总线通信的好处是,它可以提供高性能和低延迟的数据传输。此外,SocketCAN还支持多个CAN网络接口的管理,可以同时与多个CAN总线通信。 总而言之,使用SocketCAN进行CAN总线通信可以方便地在Linux中开发和调试CAN总线应用程序,提供了一套完整的硬件访问、消息发送和接收的工具和库函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值