Chinaunix首页 | 论坛 | 博客
  • 博客访问: 111698
  • 博文数量: 19
  • 博客积分: 1716
  • 博客等级: 上尉
  • 技术积分: 275
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-25 14:03
文章分类

全部博文(19)

文章存档

2011年(8)

2010年(11)

我的朋友

分类: LINUX

2011-05-12 20:32:35

Scorpio 2011-5-12 19:24:01

 

套接字的默认状态是阻塞的. 这意味着当发出一个不能立即完成的套接字调用后, 则进入睡眠, 等待相应操作完成. 可能阻塞的套接字调用有以下几种

1.输入操作, 包括read, readv, recv, recvfromrecvmsg. 如果某个进程对一个阻塞的TCP套接字调用这些输入函数, 而该套接字的接收缓冲中没有数据可读, 该进程将进入睡眠, 直到有数据到达, 哪怕只有一个字节到达. 如果你想等到有一定长度的数据到达后才返回, 可以调用readn, 或者指定MSG_WAITALL标记. 当然对于UDP套接字而言需要有一个完整的数据报可读, 才会返回. 在阻塞情况下, 如果不满足读的要求, 则会返回EWOULDBLOCK/ EAGAIN /EINPROCESS, 这三个错误标记的宏, WIN32LINUX下的定义可能不同, 具体的定义也不太一样, 可以参照

2.输出操作, 包括write, writev, send, sendtosendmsg. 在调用这些函数的时候, 内核会从用户空间将数据拷贝到套接字的发送缓冲区, 如果套接口的发送空间没有空间了则会阻塞(默认是阻塞的情况), 如果是空间不足的情况, 则会拷贝部分数据, 返回已拷贝的数据长度. 这是TCP套接口的情况. 如果是UDP套接口, 虽然UDP套接口不存在真正意义上的套接口发送缓冲, 它会冠以UDP首部和IP首部沿着协议栈向下发传送. 但可能会因为别的情况而阻塞. 具体man一下sendto的错误标记的解释.

3.接受连接, accept. 如果调用了accept, 但尚未有新的连接到来, 那么会立即返回EWOULDBLOCK/ EAGAIN/ EINPROCESS错误.

4.发起连接, connect. 一般用于TCPconnect函数. 虽然UDP也可以使用connectUDP并没有真正与peer(对端)建立连接, 只是使内核保存对端的IPPORT. TCP建立连接时, 会有三路握手的过程, 具体过程如下:

clip_image002[4]

上面的示意图清晰表明了三路握手的情况, 也就是说connect函数直到收到对于自己的SYNACK才会返回. 这意味着TCP每个connect总会阻塞其调用进程一个到peerRTT时间. 当然如果客户端和服务器在同一主机上, 连接就会立即建立而返回.

 

以上4种情况说明了非阻塞IO发生的具体情况.

 

对于一个不能立即满足的非阻塞IO操作, SystemV会返回EAGAIN错误. Berkeley的实现则返回EWOULDBLOCKEINPROCESS, 这些值的定义不同的系统可能不同, 具体查看一下. 或者可以下面的语句:

    int ret = connect(sfd, &sAddr, addrLen);

    if (ret < 0 && (errno != EAGAIN || errno != EWOULDBLOCK || errno != EINPROCESS))

    {

        return -1;

    }

 

 

Scorpio 2011-5-12 20:28:33

阅读(2385) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~