Linux下socket设置为非阻塞方式和fcntl系统调用
linux async 异步用法

linux async 异步用法
在Linux中,异步(asynchronous)操作是一种非阻塞的操作方式,可以在执行一个操作时继续执行其他任务,而不需要等待该操作完成。
这种方式可以提高程序的响应速度和并发性。
在Linux中,通常使用以下方法实现异步操作:
1. 使用非阻塞I/O:通过将文件描述符设置为非阻塞模式,可以在读写文件时立即返回,而不是等待数据准备好或者写入完成。
可以使用`fcntl()`函数将文件描述符设置为非阻塞模式,或者使用`O_NONBLOCK`标志在调用`open()`函数时指定。
2. 使用信号(signal):通过注册信号处理函数,可以在某个事件发生时,立即响应该事件而不需要等待。
可以使用`signal()`函数注册信号处理函数,当指定的信号发生时,执行注册的处理函数。
3. 使用回调函数(callback):在执行某个操作时,可以指定一个回调函数,当该操作完成时,系统会调用该回调函数。
可以通过函数指针或者函数对象来指定回调函数。
4. 使用多线程或者多进程:可以将耗时的操作放在单独的线程或进程中执行,以避免阻塞主线程或进程的执行。
在多线程或者多进程中,可以使用线程或进程间的同步机制(如锁、条件变量、信号量等)来协调不同线程或进程之间的操作。
5. 使用事件驱动库:可以使用一些基于事件驱动的库,如libevent、libuv 等,来实现异步操作。
这些库提供了一套异步操作的接口和事件循环机制,开发者可以通过注册回调函数处理特定事件。
Linuxfcntl函数详解

Linuxfcntl函数详解功能描述:根据⽂件描述词来操作⽂件的特性。
⽂件控制函数 fcntl -- file control头⽂件:#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()针对(⽂件)描述符提供控制.参数fd是被参数cmd操作(如下⾯的描述)的描述符. 针对cmd的值,fcntl能够接受第三个参数(arg)fcntl函数有5种功能: 1.复制⼀个现有的描述符(cmd=F_DUPFD). 2.获得/设置⽂件描述符标记(cmd=F_GETFD或F_SETFD).3.获得/设置⽂件状态标记(cmd=F_GETFL或F_SETFL).4.获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).5.获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).cmd选项:F_DUPFD 返回⼀个如下描述的(⽂件)描述符: (1)最⼩的⼤于或等于arg的⼀个可⽤的描述符 (2)与原始操作符⼀样的某对象的引⽤ (3)如果对象是⽂件(file)的话,返回⼀个新的描述符,这个描述符与arg共享相同的偏移量(offset) (4)相同的访问模式(读,写或读/写) (5)相同的⽂件状态标志(如:两个⽂件描述符共享相同的状态标志) (6)与新的⽂件描述符结合在⼀起的close-on-exec标志被设置成交叉式访问execve(2)的系统调⽤F_GETFD 取得与⽂件描述符fd联合close-on-exec标志,类似FD_CLOEXEC.如果返回值和FD_CLOEXEC进⾏与运算结果是0的话,⽂件保持交叉式访问exec(), 否则如果通过exec运⾏的话,⽂件将被关闭(arg被忽略)F_SETFD 设置close-on-exec旗标。
linux socket编程基础(必读)

(2) void bcopy(const void * src,void * dest,int n):从参数 src 指定 的内存区域拷贝指定数目的字节内容到参数 dest 指定的内存区域。
在调用函数 connect 之前,客户机需要指定服务器进程的套接字地址。客户 机一般不需要指定自己的套接字地址(IP 地址和端口号),系统会自动从1024 至5000的端口号范围内为它选择一个未用的端口号,然后以这个端口号和本机 的 IP 地址填充这个套接字地址。
客户机调用函数 connect 来主动建立连接。这个函数将启动 TCP 协议的3次 握手过程。在建立连接之后或发生错误时函数返回。连接过程可能出现的错误情 况有:
(2) 如果远程 TCP 协议返回一个 RST 数据段,函数立即以错误返回,错 误类型为 ECONNREFUSED。当远程机器在 SYN 数据段指定的目的端口号处
没有服务进程在等待连接时,远程机器的 TCP 协议将发送一个 RST 数据段,向 客户机报告这个错误。客户机的 TCP 协议在接收到 RST 数据段后不再继续发送 SYN 数据段,函数立即以错误返回。
(3) int bcmp(const void * s1,const void * s2,int n):比较参数 s1指 定的内存区域和参数 s2指定的内存区域的前 n 个字节内容,如果相同则返回0, 否则返回非0。
注:以上函数的原型定义在 strings.h 中。 以 mem 开头的函数有: (1) void * memset(void * s,int c,size_t n):将参数 s 指定的内存区 域的前 n 个字节设置为参数 c 的内容。 (2) void * memcpy(void * dest,const void * src,size_t n):功能同 bcopy (),区别:函数 bcopy()能处理参数 src 和参数 dest 所指定的区域有重叠的 情况,memcpy()则不能。 (4) int memcmp(const void * s1,const void * s2,size_t n):比较参 数 s1和参数 s2指定区域的前 n 个字节内容,如果相同则返回0,否则返回非0。 注:以上函数的原型定义在 string.h 中。 9、 基本套接字函数 (1) socket() #include<sys/types.h> #include<sys/socket.h>
Linux内核中系统调用详解

Linux内核中系统调用详解什么是系统调用?(Linux)内核中设置了一组用于实现各种系统功能的子程序,称为系统调用。
用户可以通过系统调用命令在自己的应用程序中调用它们。
从某种角度来看,系统调用和普通的函数调用非常相似。
区别仅仅在于,系统调用由(操作系统)核心提供,运行于核心态;而普通的函数调用由函数库或用户自己提供,运行于用户态。
随Linux核心还提供了一些(C语言)函数库,这些库对系统调用进行了一些包装和扩展,因为这些库函数与系统调用的关系非常紧密,所以习惯上把这些函数也称为系统调用。
为什么要用系统调用?实际上,很多已经被我们习以为常的C语言标准函数,在Linux 平台上的实现都是靠系统调用完成的,所以如果想对系统底层的原理作深入的了解,掌握各种系统调用是初步的要求。
进一步,若想成为一名Linux下(编程)高手,也就是我们常说的Hacker,其标志之一也是能对各种系统调用有透彻的了解。
即使除去上面的原因,在平常的编程中你也会发现,在很多情况下,系统调用是实现你的想法的简洁有效的途径,所以有可能的话应该尽量多掌握一些系统调用,这会对你的程序设计过程带来意想不到的帮助。
系统调用是怎么工作的?一般的,进程是不能访问内核的。
它不能访问内核所占内存空间也不能调用内核函数。
(CPU)(硬件)决定了这些(这就是为什么它被称作"保护模式")。
系统调用是这些规则的一个例外。
其原理是进程先用适当的值填充(寄存器),然后调用一个特殊的指令,这个指令会跳到一个事先定义的内核中的一个位置(当然,这个位置是用户进程可读但是不可写的)。
在(Intel)CPU中,这个由中断0x80实现。
硬件知道一旦你跳到这个位置,你就不是在限制模式下运行的用户,而是作为操作系统的内核--所以你就可以为所欲为。
进程可以跳转到的内核位置叫做sysem_call。
这个过程检查系统调用号,这个号码告诉内核进程请求哪种服务。
然后,它查看系统调用表(sys_call_table)找到所调用的内核函数入口地址。
Socket调用方式(同步,异步,阻塞,非阻塞)

Socket调⽤⽅式(同步,异步,阻塞,⾮阻塞)同步:我调⽤⼀个功能,该功能没有结束前,我死等结果。
异步:当⼀个异步过程调⽤发出后,调⽤者不能⽴刻得到结果。
该功能在完成后,通过状态、通知和回调来通知调⽤者。
同步和⾮同步关注的是调⽤者是否等待等待调⽤结果。
举个通俗的例⼦:你打电话问书店⽼板有没有《分布式系统》这本书,如果是同步通信机制,书店⽼板会说,你稍等,”我查⼀下",然后开始查啊查,等查好了(可能是5秒,也可能是⼀天)告诉你结果(返回结果)。
⽽异步通信机制,书店⽼板直接告诉你我查⼀下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。
然后查好了,他会主动打电话给你。
在这⾥⽼板通过“回电”这种⽅式来回调。
阻塞:调⽤我(函数),我(函数)没有接收完数据或者没有得到结果之前,我不会返回。
⾮阻塞:调⽤我(函数),我(函数)⽴即返回通知调⽤者以最常⽤的send和recv两个函数为例⽐如你调⽤send函数发送⼀定的Byte,在系统内部send做的⼯作其实只是把数据传输(Copy)到TCP/IP协议栈的输出缓冲区,它执⾏成功并不代表数据已经成功的发送出去了,如果TCP/IP协议栈没有⾜够的可⽤缓冲区来保存你Copy过来的数据的话...这时候就体现出阻塞和⾮阻塞的不同之处了:对于阻塞模式的socket send函数将不返回直到系统缓冲区有⾜够的空间把你要发送的数据Copy过去以后才返回,⽽对于⾮阻塞的socket来说send会⽴即返回WSAEWOULDDBLOCK告诉调⽤者说:"发送操作被阻塞了!!!你想办法处理吧..."对于recv函数,同样道理,对于阻塞模式的socket来说如果TCP/IP协议栈的接收缓冲区没有通知⼀个结果给它它就⼀直不返回:耗费着系统资源....对于⾮阻塞模式的socket该函数会马上返回,然后告诉你:WSAEWOULDDBLOCK---"现在没有数据,回头再来看看"阻塞I/O模型:⾮阻塞I/O模型:阻塞和⾮阻塞关注的是调⽤者在等待调⽤结果时的状态。
非阻塞connect写法

非阻塞connect写法
非阻塞connect是指在网络编程中,客户端发起连接请求时不
会被阻塞,而是立即返回,可以在后续的代码中通过轮询或者回调
的方式来获取连接是否建立成功。
在实际编程中,可以通过设置套
接字为非阻塞模式来实现非阻塞connect。
在C/C++语言中,可以使用以下步骤来实现非阻塞connect的
写法:
1. 创建套接字,使用socket函数创建套接字。
2. 设置为非阻塞模式,使用fcntl函数或者ioctl函数将套接
字设置为非阻塞模式。
3. 发起连接请求,使用connect函数向服务器发起连接请求。
4. 检测连接状态,在非阻塞模式下,connect函数会立即返回,并不保证连接一定会成功建立。
可以使用select函数、poll函数
或者epoll函数等进行轮询,或者使用回调函数来检测连接状态。
5. 处理连接结果,根据轮询或者回调的结果,可以判断连接是
否成功建立,如果连接成功,则可以进行后续的数据传输操作;如
果连接失败,则可以进行相应的处理,比如重新发起连接请求或者
进行错误处理。
在Python语言中,可以使用socket模块提供的
setblocking(False)方法将套接字设置为非阻塞模式,然后使用connect方法发起连接请求,最后通过select模块进行状态检测。
总之,非阻塞connect的写法需要将套接字设置为非阻塞模式,并通过轮询或者回调来检测连接状态,以实现在发起连接请求时不
被阻塞的效果。
fcntl函数介绍

fcntl函数介绍 1、fcntl:manipulate file descriptor 1)简介:fcntl(file control)函数可执⾏各种描述符控制操作。
#include <unistd.h>#include <fcntl.h>int fcntl(int fd, int cmd, ... /* arg */ ); 2)正确的使⽤⽅法(以设置“⾮阻塞”标记为例):int flags;// 先获取当前的flagsif ((flags = fcntl(sockfd, F_GETFL, 0)) < 0)// 错误处理...flags |= O_NONBLOCK; // 加上“⾮阻塞”flagif (fcntl(sockfd, F_SETFL, flags) < 0) // 设置新的flags// 错误处理... 3)常⽤⽤法: (1)把⼀个套接字设置为⾮阻塞型:cmd为F_SETFL,flags“包含”O_NONBLOCK。
(2)把⼀个套接字设置成⼀旦其状态发⽣变化,内核就产⽣⼀个SIGIO:cmd为F_SETFL,flags“包含”O_ASYNC。
(3)关于套接字的当前属主。
cmd为F_SETOWN:指定⽤于接收SIGIO或SIGURG信号的套接字属主(进程ID或进程组ID)。
SIGIO是套接字被设置为信号驱动式I/O 型后产⽣的,⽽SIGURG是在新的带外数据到达套接字时产⽣的。
SIGIO与SIGURG与其他信号的不同之处在于,这两个信号仅在已使⽤F_SETOWN命令给相关套接字指派了属主后才会产⽣。
F_SETOWN命令对应的arg参数是正整数时,指出接收信号的进程ID;为负整数时,其绝对值指出接收信号的进程组ID(此时整个进程组中的所有进程接收信号)。
cmd为F_GETOWN:返回套接字的当前属主。
(4)记录上锁。
记录上锁的Posix接⼝是fcntl函数。
linux、glibc中socket系统调用实现

/* %eax is < 0 if there was an error. */ cmpl $-125, %eax jae SYSCALL_ERROR_LABEL
/* Successful; return the syscall's value. */ L(pseudo_end):
ret ……
代码# define __socket socket 将__socket 定义为 socket,因此 ENTRY (__socket)即为 ENTRY (socket) 在这段汇编代码中,我们在 eax 保存当前系统调用号(这里是 socketcall),查看 SYS_ify 的定义,在 glibc/sysdeps/unix/sysv/linux/i386/sysdep.h 中:
#ifndef _SYS_SOCKETCALL_H #define _SYS_SOCKETCALL_H 1
/* Define unique numbers for the operations permitted on socket. Linux uses a single system call for all these functions. The relevant code file is /usr/include/linux/net.h. We cannot use a enum here because the values are used in assembler code. */
movl $SYS_ify(socketcall), %eax /* System call number in %eax. */
/* Use ## so `socket' is a separate token that might be #define'd. */
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux下socket设置为非阻塞方式和fcntl系统调用
[日期:2011-04-16] 来源:Linux社区作者:Linux
用以下方法将socket设置为非阻塞方式
int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
用以下方法将socket设置为非阻塞方式
int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
将非阻塞的设置回阻塞可以用
int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, flags & ~O_NONBLOCK);
功能描述:根据文件描述词来操作文件的特性。
用法:
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
参数:
fd:文件描述词。
cmd:操作命令。
arg:供命令使用的参数。
lock:同上。
有以下操作命令可供使用
一. F_DUPFD :复制文件描述词。
二. FD_CLOEXEC :设置close-on-exec标志。
如果FD_CLOEXEC位是0,执行execve的过程中,文件保持打开。
反之则关闭。
三. F_GETFD :读取文件描述词标志。
四. F_SETFD :设置文件描述词标志。
五. F_GETFL :读取文件状态标志。
六. 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。
七. F_GETLK, F_SETLK 和F_SETLKW :获取,释放或测试记录锁,使用到的参数是以下结构体指针:
F_SETLK:在指定的字节范围获取锁(F_RDLCK, F_WRLCK)或者释放锁(F_UNLCK)。
如果与另一个进程的锁操作发生冲突,返回-1并将errno设置为EACCES或EAGAIN。
F_SETLKW:行为如同F_SETLK,除了不能获取锁时会睡眠等待外。
如果在等待的过程中接收到信号,会立即返回并将errno置为EINTR。
F_GETLK:获取文件锁信息。
F_UNLCK:释放文件锁。
为了设置读锁,文件必须以读的方式打开。
为了设置写锁,文件必须以写的方式打开。
为了设置读写锁,文件必须以读写的方式打开。
八. 信号管理
F_GETOWN, F_SETOWN, F_GETSIG 和F_SETSIG 被用于IO可获取的信号。
F_GETOWN:获取当前在文件描述词fd上接收到SIGIO 或SIGURG事件信号的进程或进程组标识。
F_SETOWN:设置将要在文件描述词fd上接收SIGIO 或SIGURG事件信号的进程或进程组标识。
F_GETSIG:获取标识输入输出可进行的信号。
F_SETSIG:设置标识输入输出可进行的信号。
使用以上命令,大部分时间程序无须使用select()或poll()即可实现完整的异步I/O。
九. 租约(Leases)
F_SETLEASE 和F_GETLEASE 被用于当前进程在文件上的租约。
文件租约提供当一个进程试图打开或折断文件内容时,拥有文件租约的进程将会被通告的机制。
F_SETLEASE:根据以下符号值设置或者删除文件租约
1.F_RDLCK设置读租约,当文件由另一个进程以写的方式打开或折断内容时,拥有租约的当前进程会被通告。
2.F_WRLCK设置写租约,当文件由另一个进程以读或以写的方式打开或折断内容时,拥有租约的当前进程会被通告。
3.F_UNLCK删除文件租约。
F_GETLEASE:获取租约类型。
十.文件或目录改变通告
(linux 2.4以上)当fd索引的目录或目录中所包含的某一文件发生变化时,将会向进程发出通告。
arg参数指定的通告事件有以下,两个或多个值可以通过或运算组合。
1.DN_ACCESS 文件被访问(read, pread, readv)
2.DN_MODIFY 文件被修改(write, pwrite,writev, truncate, ftruncate)
3.DN_CREATE 文件被建立(open, creat, mknod, mkdir, link, symlink, rename)
4.DN_DELETE 文件被删除(unlink, rmdir)
5.DN_RENAME 文件被重命名(rename)
6.DN_ATTRIB 文件属性被改变(chown, chmod, utime[s])
返回说明:
成功执行时,对于不同的操作,有不同的返回值
F_DUPFD:新文件描述词
F_GETFD:标志值
F_GETFL:标志值
F_GETOWN:文件描述词属主
F_GETSIG:读写变得可行时将要发送的通告信号,或者0对于传统的SIGIO行为
对于其它命令返回0。
失败返回-1,errno被设为以下的某个值
EACCES/EAGAIN: 操作不被允许,尚未可行
EBADF: 文件描述词无效
EDEADLK: 探测到可能会发生死锁
EFAULT: 锁操作发生在可访问的地址空间外
EINTR: 操作被信号中断
EINVAL:参数无效
EMFILE: 进程已超出文件的最大可使用范围
ENOLCK: 锁已被用尽
EPERM:权能不允许
struct flock {
short l_type; /* 锁类型:F_RDLCK, F_WRLCK, F_UNLCK */
short l_whence; /* l_start字段参照点:SEEK_SET(文件头), SEEK_CUR(文件当前位置), SEEK_END(文件尾) */ off_t l_start; /* 相对于l_whence字段的偏移量*/
off_t l_len; /* 需要锁定的长度*/
pid_t l_pid; /* 当前获得文件锁的进程标识(F_GETLK)*/
};。