当使用socket()函数和WSASocket()函数创建套接字时,默认都是阻塞的。在创建套接字之后,通过调用ioctlsocket()函数,将该套接字设置为非阻塞模式。函数的第一个参数是套接字,第二个参数设置为FIONBIO,第三个参数设置为unsigned long类型的非零值。下面代码清单演示了如何用ioctlsocket()函数,设置套接字为非阻塞模式。

SOCKET            s;                                                                       //套接字

unsigned long ul = 1;                                                                          //设置套接字选项

int                        nRet;                                                                 //返回值

s = socket(AF_INET, SOCK_STREAM, 0);                            //创建套接字

nRet = ioctlsocket(s, FIONBIO, (unsigned long*)&ul);                 //设置套接字非阻塞模式

if (nRet == SOCKET_ERROR)

{

//设置套接字非阻塞模式,失败处理

}

套接字设置为非阻塞模式后,在调用Windows Sockets API函数时,调用函数会立即返回。大多数情况下,这些函数调用都会调用“失败”,并返回WSAEWOULDBLOCK错误代码。说明请求的操作在调用期间内没有时间完成。通常,应用程序需要重复调用该函数,直到获得成功返回代码。下面程序清单示例了一个在非阻塞套接字上反复调用recv()函数,直到收到1024个字节的数据。

#define                        NUM_REQUIRED              1024         //需要读入数据的大小

#define                        MAX_SIZE                            2048         //输入缓冲区的大小

TCHAR                        buff[MAX_SIZE];                            //输入缓冲区

bool                    close;                                                      //对方关闭了连接

SOCKET                     sock;                                              //Windows sockets

void ReadData(void)

{

int nTotal = 0;                                                            //已经读入缓冲区字节数

int nRead = 0;                                                           //在调用recv时实际读入字节数

int nLeft = 0;                                                              //剩下数据的字节数

int nBytes = 0;                                                           //当前已读数据在缓冲区的位置

nLeft = NUM_REQUIRED;

while (nTotal != NUM_REQUIRED)//已经读入缓冲区的字节数不等于需要读入的大小时

{

nRead = recv(sock, &buff[MAX_SIZE - nBytes], nLeft, 0);   //接收数据

if(SOCKET_ERROR == nRead)                                              //读操作失败

{

int err = WSAGetLastError();

if(WSAEWOULDBLOCK == err)                                     //接收数据缓冲区不可用

{

continue;                                                                   //接着读取数据

}else if(WSAETIMEDOUT == err || WSAENETDOWN == err)      //连接已经断开

{

close = TRUE;                                                                            //函数退出

break;

}

}

if( 0 == nRead)                                      //客户端关闭了连接

{

close = TRUE;                              //函数退出

break;

}

nTotal += nRead;

nLeft -= nRead;

nBytes += nRead;

}

return;

}

在该程序中,通过调用WSAGetLastError()函数获得recv()函数返回的错误代码。当返回WSAEWOULDBLOCK错误时,说明此时套接字的缓冲区还没有准备好的数据。需要继续调用该函数。

在该程序中,还对recv()函数返回的其他错误代码进行处理。WSAETIMEDOUT和WSAENETDOWN错误说明,此时由于网络系统的原因与对方的连接已经断开了。当函数返回0时,说明对方关闭了连接。在程序中通过设置close布尔变量值为TRUE,表明与对方的连接已经断开。调用break语句跳出while循环体,函数退出。在开发中,应该根据具体情况对函数返回的错误值进行具体处理。

不同的Windows Sockets API函数,在调用失败时返回的WSAEWOULDBLOCK错误代码具有不同的含义。表对几个Windows Sockets API函数返回WSAEWOULDBLOCK错误的含义进行了总结。

表  WSAEWOULDBLOCK的含义

函数名

说明

accept()和WSAAcept()

应用程序没有收到连接请求

recv()、WSARecv()、recvfrom()和WSARecvfrom()

接收缓冲区没有收到数据

send()、WSASend()、sendfrom()和WSASendfrom()

发送缓冲区此时不可用

connect()和WSAConnect()

连接未能立即完成

closescoket()

通常情况下意味着应用程序使用SO_LINGER选项并且设置了一个非零的超时值,调用了setsocketopt()函数

需要说明的是并非所有的Windows Sockets API在非阻塞模式下调用,都会返回WSAEWOULDBLOCK错误。例如,以非阻塞模式的套接字为参数调用bind()函数时,就不会返回该错误代码。当然,在调用WSAStartup()函数时更不会返回该错误代码,因为该函数是应用程序第一调用的函数,当然不会返回这样的错误代码。

要将套接字设置为非阻塞模式,除了使用ioctlsocket()函数之外,还可以使用WSAAsyncselect()和WSAEventselect()函数。当调用该函数时,套接字会自动地设置为非阻塞方式。在后续章节中,讲解该函数的使用方法。

设置非阻塞的套接字Socket的更多相关文章

  1. Java套接字Socket编程--TCP参数

    在Java的Socket中,主要包含了以下可设置的TCP参数. 属性 说明 默认值 SO_TIMEOUT 对ServerSocket来说表示等待连接的最长空等待时间; 对Socket来说表示读数据最长 ...

  2. pythonl练习笔记——PythonNet 套接字socket

    1 套接字socket 1.1 套接字概述 套接字,一种网络通讯工具:用于进行网络间的通信,是一种特殊文件类型, 套接字,是一个通信链的句柄,用于描述IP地址和端口,实现向网络发出请求或应答网络请求. ...

  3. 网络编程 套接字socket TCP UDP

    网络编程与套接字 网络编程 网络编程是什么: ​ 网络通常指的是计算机中的互联网,是由多台计算机通过网线或其他媒介相互链接组成的 ​ 编写基于网络的应用程序的过程序称之为网络编程. 网络编程最主要的工 ...

  4. Linux进程间通信(八):流套接字 socket()、bind()、listen()、accept()、connect()、read()、write()、close()

    前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程.通常我们使用socket进行网络编 ...

  5. Linux进程间通信(九):数据报套接字 socket()、bind()、sendto()、recvfrom()、close()

    前一篇文章,Linux进程间通信——使用流套接字介绍了一些有关socket(套接字)的一些基本内容,并讲解了流套接字的使用,这篇文章将会给大家讲讲,数据报套接字的使用. 一.简单回顾——什么是数据报套 ...

  6. [置顶] Java套接字Socket编程

    1)概念 网络编程基本模型就客户端到服务器的模型,也就是我们常见的C/S模型.简单的说就是两个进程间相互通信的过程.即通信双方一方作为服务器等待客户端提出请求并给以回应,另一方作为客户端向服务器提出请 ...

  7. 面向对象之套接字(socket)和黏包

    一丶套接字(socket) tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端 基于UDP协议的socket server端: import socket udp_sk = socke ...

  8. 网络编程(二)--TCP协议、基于tcp协议的套接字socket

    一.TCP协议(Transmission Control Protocol 传输控制协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会 ...

  9. 进程间的通信—套接字(socket)

      前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程.通常我们使用socket进行网 ...

随机推荐

  1. SPSS转换菜单:创建时间序列

    SPSS转换菜单:创建时间序列 1.概念:"创建时间序列"对话框允许您基于现有数值型时间序列变量的函数创建新的变量.这些转换后的值在时间序列分析中非常有用. 2.操作:转换-创建时 ...

  2. CCflow与基础框架组织机构整合

    SELECT No,Name,Pass,FK_Dept,SID FROM Port_Emp SELECT No,Name,ParentNo FROM Port_Dept SELECT No,Name, ...

  3. nodeType介绍及应用示例

    一,DOM中的节点类型介绍 DOM将一份文档抽象为一棵树,而树又由众多不同类型的节点构成. 元素节点是DOM中的最小单位节点,它包括了各种标签,比如表示段落的p,表示无序列表的ul等. 文本节点总是被 ...

  4. ubuntu中搭建基本的开发环境

    1.搭建基本开发环境: sudo apt-get install build-essential 2.安装语法.词法分析器 sudo apt-get install bison flex 3.安装C函 ...

  5. Java面试宝典(5)算法

    二.算法与编程 1.编写一个程序,将a.txt文件中的单词与b.txt文件中的单词交替合并到c.txt文件中,a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格进行分隔. 答: pack ...

  6. 提交disable的Select值到后台

    需求:界面上把select控件disable,然后将默认值传到后台 问题1:select disable: js中可以这样写: document.getElementById("provin ...

  7. 翻译 What is the concept of Service Container in Laravel?

    原文链接: https://stackoverflow.com/questions/37038830/what-is-the-concept-of-service-container-in-larav ...

  8. WPF datagrid/gridcontrol 中选中多行,复制粘贴到excel或其他文本编辑器中

    wpf中 data grid 开启自带的选中,然后复制,可以到excel中直接粘贴,在某些业务场景中很实用,方便.开启也很简单: SelectionMode="Row" 加上这个, ...

  9. fiddler增加ip以及响应时间列

    最近打算看一下移动端app的响应等请求,这里打算用fillder来查看appium的模拟出发请求的操作来查看结果, 所以我们需要在左侧的面板增加我们所需要的ip,响应时间等数据以方便我们查看 fidd ...

  10. hdu 5791 思维dp

    题目描述: 求序列A,B的公共子序列个数: 基本思路: 想到了dp,选的状态也对,但是就是就是写不出状态转移方程,然后他们都出了,到最后我还是没出,很难受,然后主要是没有仔细考虑dp[i][j],dp ...