实验8非阻塞I/O

非阻塞I/O

1 阻塞socket 和非阻塞socket

设置一个套接字为非阻塞模式,相当于通知内核当一个套接字相关的I/O 操作不能立刻

完成的时候,不要将调用者设为休眠状态,而是应该返回一个错误代码。其区别如下图所示:

内核

应用

read, recvfrom(write,sendto,accept,connect)

wait for data come in

copy data

copy completely

return

continue to process with data

内核

应用

read

return EWOULDBLOCK immediately

read

return EWOULDBLOCK immediately

read

拷贝数据到用户空间

return success

处理数据

1.1 读操作

对于阻塞的socket,socket  的接收缓冲区中没有数据时,read 调用会一直阻塞住,直

到有数据到来才返回。当socket 缓冲区中的数据量小于期望读取的数据量时,返回实际读

取的字节数。当sockt 的接收缓冲区中的数据大于期望读取的字节数时,读取期望读取的字

节数,返回实际读取的长度。

对于非阻塞socket 而言,socket 的接收缓冲区中有没有数据,read 调用都会立刻返回。

接收缓冲区中有数据时,与阻塞socket 有数据的情况是一样的,如果接收缓冲区中没有数

据,则返回错误号为EWOULDBLOCK,

表示该操作本来应该阻塞的,但是由于本socket 为非阻塞的socket,因此立刻返回,遇

到这样的情况,可以在下次接着去尝试读取。如果返回值是其它负值,则表明读取错误。

因此,非阻塞的read 调用一般这样写:

if ((nread  = read(sock_fd, buffer, len)) < 0)

{

if (errno == EWOULDBLOCK)

{

return 0; //表示没有读到数据

}else return -1; //表示读取失败

}else return  nread;读到数据长度

1.2 写操作

对于写操作write,原理是类似的,非阻塞socket  在发送缓冲区没有空间时会直接返回错

误号EWOULDBLOCK,表示没有空间可写数据,如果错误号是别的值,则表明发送失败。

如果发送缓冲区中有足够空间或者是不足以拷贝所有待发送数据的空间的话,则拷贝前面N

个能够容纳的数据,返回实际拷贝的字节数。

而对于阻塞Socket 而言,如果发送缓冲区没有空间或者空间不足的话,write 操作会直

接阻塞住,如果有足够空间,则拷贝所有数据到发送缓冲区,然后返回。

非阻塞的write 操作一般写法是:

int write_pos = 0;

int  nLeft = nLen;

while (nLeft > 0)

{

int nWrite = 0;

if ((nWrite = write(sock_fd, data +  write_pos, nLeft)) <= 0)

{

if (errno == EWOULDBLOCK) nWrite =  0;

else return -1; //表示写失败

}

nLeft -= nWrite;

write_pos += nWrite;

}

return nWrite

1.3 建立连接

阻塞方式下,connect 首先发送SYN 请求道服务器,当客户端收到服务器返回的SYN

确认时,则connect 返回。否则的话一直阻塞。

非阻塞方式,connect 将启用TCP 协议的三次握手,但是connect 函数并不等待连接建立

好才返回,而是立即返回。返回的错误码为EINPROGRESS,表示正在进行某种过程。接收


连接对于阻塞方式的倾听socket,accept 在连接队列中没有建立好的连接时将阻塞,直到有可

用的连接,才返回。

阻塞倾socket, 没有连接时都立即返回,没有连接时,返回的错误码

EWOULDBLOCK,表示本来应该阻塞。

2 无阻塞的设置方法

方法一:fcntl

int flag=fcntl(fd, F_GETFL, 0);

fcntl(fd, F_SETFL, flag|O_NONBLOCK) ;

方法二:ioctl

int b_on = 1;

ioctl (fd, FIONBIO, &b_on);

3 程序分析:

下面的程序利用非阻塞模式下的conncet 函数,进行端口扫描。

#include <stdio.h>

#include <sys/time.h>

#include <stdlib.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <errno.h>

#include <sys/select.h>

#include <fcntl.h>

//使用方法:scan 192.168.1.1  192.168.2.10 89 500

int main(int argc, char* argv[])

{

long startip,endip,startport,endport;

if(!(argc==4||argc==5||argc==1))

{printf("参数错误\r\n");exit(-1);};

if(argc==1)

{

startip=inet_addr("127.0.0.1");

endip=startip;

startport=1;

endport=65535;

}


if(argc==4)

{

startip=inet_addr(argv[1]);

endip=startip;

startport=atoi(argv[2]);

endport=atoi(argv[3]);

}

if(argc==5)

{

startip=inet_addr(argv[1]);

endip=inet_addr(argv[2]);

startport=atoi(argv[3]);

endport=atoi(argv[4]);

}

if(startip==INADDR_NONE||endip==INADDR_NONE)

{printf("error ip address\r\n");exit(-1);};

if(startport==0||endport==0)

{printf("error port!\r\n");exit(-1);};

long i,j;

for(i=ntohl(startip);i<=ntohl(endip);i++)

{

//i 表示IP 地址的变量(PC 机顺序)

for(j=startport;j<=endport;j++)

{

//j 表示端口

int fd=socket(AF_INET,SOCK_STREAM,0);

struct sockaddr_in  s;

s.sin_addr.s_addr=htonl(i);//i 转换为网络字节序的IP 地址

s.sin_port=htons(j);

s.sin_family=AF_INET;

int flag;

fcntl(fd,F_GETFL,&flag);

fcntl(fd,F_SETFL,flag|O_NONBLOCK);//设置为非阻塞

int cret=connect(fd,(struct sockaddr*)&s,sizeof  s);

if(cret==0)

{

printf("%s:%d  is open\r\n",inet_ntoa(s.sin_addr),j);

close(fd);

continue;

}

/*由于是非阻塞工作模式,因此对于来不及返回0 connect 函数,

errno 应该为EINPROGRESS,表示正在建立这个连接*/


if(errno!=EINPROGRESS){close(fd);continue;};

fd_set wset;

FD_ZERO(&wset);

FD_SET(fd,&wset);

struct timeval timeout;

timeout.tv_sec=0;

timeout.tv_usec=10000;//10 毫秒

int rs=select(fd+1,NULL,&wset,NULL,&timeout);//等待10 毫秒,等待

这个fd 是否可写,可写表示已经建立了连接

int error=0;

int len=sizeof error;

if((rs==1)&&(getsockopt(fd,SOL_SOCKET,SO_ERROR,&error,&len)==0))

{

//error 如果不为零,则证明对方的端口是开放的

if(error==0)

printf("%s:%d is  open\r\n",inet_ntoa(s.sin_addr),j);

}

close(fd);

continue;

}

}

}


更多相关文章
  •  在网络应用中,一般可以采用同步I/O(阻塞I/O)和非阻塞I/O两种方式进行数据通讯.这两种方式并非互相排斥和互相取代.我们可以在平时的应用中单独采用其中一种通讯方式,也可以混合使用这两种通讯方式.在本文中就什么是非阻塞I/O以及为什么要使用这种通讯方式进行了介绍,在下一篇文章中给出了一个简单的例 ...
  • 网络IO之阻塞、非阻塞、同步、异步总结
    1.前言 在网络编程中,阻塞.非阻塞.同步.异步经常被提到.unix网络编程第一卷第六章专门讨论五种不同的IO模型,Stevens讲的非常详细,我记得去年看第一遍时候,似懂非懂,没有深入理解.网上有详细的分析:http://blog.csdn.net/historyasamirror/article ...
  • 参考博客: ①setsockopt()函数使用详解:http://blog.csdn.net/tody_guo/article/details/5972588 ②setsockopt :SO_LINGER 选项设置:http://blog.csdn.net/factor2000/article/de ...
  • package test;import java.net.*;import java.nio.*;import java.nio.channels.*;import java.io.*;publicclass FirstNonBlockingIO{    publicstaticvoid main( ...
  • 网络编程释疑之:同步,异步,阻塞,非阻塞
    一讲到网络编程的I/O模型,总会涉及到这几个概念.问了很多人,没几个能清晰地讲出他们之间的区别联系,甚至在网络上也有很多不同的观点,也不知是中国文字释义的博大精深,还是本来这几个概念就是绕人不倦.今天我也来给大家讲解一下我对这几个概念的理解.既然网络上众说纷纭,不如找个权威参考一下,这个权威就是&l ...
  • 采用Swing 布局 NIO非阻塞式仿飞秋聊天程序, 切换皮肤颜色什么的小功能以后慢慢做 启动主程序. 当用户打开主程序后自动获取局域网段IP可以在 设置 --> IP网段过滤, 拥有 JMF 视频聊天功能(取得视频流读取到ByteBuffer然后写入DatagramChannel), 其实什 ...
  • 怎样理解阻塞非阻塞与同步异步的区别
    怎样理解阻塞非阻塞与同步异步的区别?[整理自知乎]"阻塞"与"非阻塞"与"同步"与"异步"不能简单的从字面理解,提供一个从分布式系统角度的回答.1.同步与异步同步和异步关注的是消息通信机制(synchronous com ...
  • 本文转载自:http://blog.csdn.net/historyasamirror/article/details/5778378 尊重及感谢原作者!言归正传.同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-block ...
一周排行