select函数决定一个或者多个套接字(socket)的状态,如果需要的话,等待执行异步I/O。

int select(

__in        int    nfds,

__inout    fd_set *readfds,

__inout  fd_set *writefds,

__inout  fd_set *exceptfds,

__int       const struct timeval *timeout

);

参数

nfds:忽略。

readnfds: 指向检查可读性的套接字集合的可选的指针。

writefds: 指向检查可写性的套接字集合的可选的指针。

exceptfds: 指向检查错误的套接字集合的可选的指针。

timeout: select函数需要等待的最长时间,需要以TIMEVAL结构体格式提供此参数,对于阻塞操作,此参数为null。

返回值

select函数返回那些准备好并且包含在fd_set结构体的套接字的总数,如果超时,则返回0;如果错误发生,返回SOCKET_ERROR。如果返回值为SOCKET_ERROR,可以通过WSAGetLastError函数检索指定的错误码。

错误码

解释

WSANOTINITIALISTED

在使用此函数之前,WSAStartup函数必须成功的执行

WSAEFALUT

套接字执行时不能分配需要的资源或者readfds、writefds、exceptfds、timeval参数不是用户地址空间的一部分。

WSAENETDOWN

网络子系统失败

WSAEINVAL

超时值不合法的,或者其他的三个参数为空。

WSAEINTR

阻塞的套接字1.1调用通过WSACancelBlockingCall取消

WSAEINPROGRESS

阻塞的套接字1.1调用正在处理或者服务提供者正在处理一个掉用户函数。

WSAENOTSOCK

描述集中包括一个不是套接字的入口。

说明

       select函数用于决定一个或者多个套接字的状态。对于每一个套接字,调用者可以请求读、写或者错误状态信息。一个请求给定状态的套接字集由fd_set结构体指定。在fd_set结构体中的套接字必须和单个服务提供者联系在一起。基于此,如果WSAPROTOCOL_INFO结构体中有相同的providerId值,套接字被认为来自同一个服务提供者。直到返回,结构体更新去反映满足指定条件套接字子集。select函数返回满足条件的套接字个数。fd_set集合可以通过一些宏手动操作。这些宏也适合伯克利套接字,但是它们的机理是根本不同的。

参数readfds指示检查套接字的可读性。当套接字在listen状态,如果已经接收一个连接请求,这个套接字会被标记为可读,例如一个accept会确保不会阻塞的完成。对于其他的套接字,可读性意味着队列中的数据适合读,当调用recv,WSARecv,WSARecvFrom或者recvfrom后不会阻塞。

对于面向连接的套接字,可读性也可以指示关闭套接字的从另一端接收的请求。如果虚电路正常关闭,并且所有的数据都已经接收,然后recv会立刻返回(没有数据接收),如果虚电路重置,recv会立刻返回错误码,例如WSAECONNRESET。如果套接字选项SO_OOBINLINE置位(参见setsockop),出现的OOB数据将会被检查。

参数writefds指示检查套接字的可写性。如果套接字处理connect调用(非阻塞的),并且完全建立连接,这时套接字是可写。如果套接字没有处理connect调用,可写性意味着担保send,sendto或者WSASendto执行成功。但是,如果len参数超过系统的缓存空间大小,它们在阻塞套接字中是可以阻塞的。不确定多长的长度是合法的,尤其在多线程环境下。

参数exceptfds指示套接字被检查OOB数据出现或者异常错误环境。

注意:OOB数据仅仅应用当SO_OOBINLINE设置为FALSE的情况下。如果一个套接字处理连接调用(非阻塞模式),试图连接的错误信息在exceptfds中,这个文档并没有定义那些错误需要包含其中。

readfd,writefds或者exceptfds中任何两个参数在调用的时候需要为null。至少一个必须为非空,并且任何一个非空描述设置必须包括至少一个套接字句柄。

总之,一个套接字将会被指定在一个特殊的集合当select返回如果:

readfds:

①     如果listen函数已经调用并且连接挂起,accept会执行成功。

②     数据适合读(如果SO_OOBINLINE置位,包括OOB数据)

③     连接被关/重置/终止

writefds:

①     如果处理一个connect调用(非阻塞),连接成功。

②     数据可以发送。

exceptfds:

①     如果处理一个connect调用(非阻塞),连接失败。

②     OOB数据适合读(仅当SO_OOBINLINE未置位)

在头文件Winsock2.h中定义四个宏来操作和检查描述集。FD_SETSIZE决定在描述集合中最大数量(FD_SETSIZE的默认值为64,此值可以在导入Winsock2.h之前通过FD_SETSIZE修改)。

使用这些宏是为了在不同的套接字环境中维护软件便利。这些宏操作和检查fd_set内容为:

FD_CLR(s, *set)

         从set集合中移除描述符s

FD_ISSET(s, *set)

         如果s在set中,返回非0,否则返回0

FD_SET(s, *set)

         增加描述符s到set中

FD_ZERO(*set)

         初始化set集合为null集合

#include<WinSock2.h>
#include<stdio.h>
#include<Windows.h>
#include<string>
#include<iostream>
#include<thread>
#include<exception>
#include<future>
#include<vector>
using namespace std;
#pragma comment(lib,"WS2_32.lib")//显示连接套接字库
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define SIZE 5 FILE * ffp;
struct fd_set rfds;
struct sockaddr_in ipadd;
struct timeval timeout = { , };
char * readbuff[] = { }; string ss;
vector<SOCKET> v;
char sztext[] = { };
char sztext1[] = { };
SOCKET s;
int n;
sockaddr_in addr, addr2;
int ret; void Close()
{
::closesocket(s);
if (!v.empty())
{
v.clear();
}
::WSACleanup();
} void Initialize()
{
WSADATA data;
WORD w = MAKEWORD(, );//版本号
//strcpy(sztext, lastSend.c_str());
::WSAStartup(w, &data); //动态链接库初始化
s = ::socket(AF_INET, SOCK_STREAM, );
n = sizeof(addr2);
addr.sin_family = AF_INET;
addr.sin_port = htons();
addr.sin_addr.S_un.S_addr = INADDR_ANY;
::bind(s, (sockaddr*)&addr, sizeof(addr));
::listen(s, SIZE);
printf("服务器已经启动\n");
} void MyRecv()
{
try{
while (true)
{
for (int i = ; i < v.size(); ++i)
{
FD_ZERO(&rfds); /* 清空集合 */
FD_SET(v.at(i), &rfds); /* 将fp添加到集合,后面的FD_ISSET和FD_SET没有必然关系,这里是添加检测 */ switch (select(, &rfds, NULL, NULL, &timeout)) //select使用
{
case -:
v.erase(v.begin() + i);
printf("客服端断开\n");
break; //select错误退出程序
case :
continue; //再次轮询
default:
if (FD_ISSET(v.at(i), &rfds)) //测试sock是否可读即是否网络上有数据
{
if (::recv(v.at(i), sztext1, sizeof(sztext1), ) != -)
{
printf("%s\r\n", sztext1);
}
else
{
v.erase(v.begin() + i);
printf("客服端断开\n");
continue;
}
ss = "有";
ss += sztext1;
strcpy(sztext, ss.c_str());
for (int j = ; j < v.size(); ++j)
{
::send(v.at(j), sztext, sizeof(sztext), );
}
}
}
}
}
}
catch (const exception& e)
{
cerr << "出错了" << endl;
Close();
}
return;
} int main()
{
SOCKET s1;
Initialize();
auto w = async(launch::async, [&]{
while (true)
{
if (v.size() < SIZE)
{
for (int i = v.size(); i < SIZE; ++i)
{
s1 = ::accept(s, (sockaddr*)&addr2, &n);
if (s1 != NULL)
{
v.push_back(s1);
printf("%s已经连接上\r\n", inet_ntoa(addr2.sin_addr));
}
}
printf("服务器接收额已满!\n");
}
}
return;
});
try{
thread t1(MyRecv);
t1.join();
}
catch (const exception& e)
{
cerr << "出错了" << endl;
}
Close();
system("pause");
return ;
}

         参数time-out控制select函数完成的时间(超过这个时间返回超时)。如果time-out是个空指针,select会一直保持阻塞指导至少一个描述符符合指定的准则。否则,time-out指向一个TIMEVAL结构体,这个结构体指定select在返回之前应该等待最大时间。当select返回,TIMEVAL结构体中的内容是不会改变的。如果TIMEVAL初始化为{0,0},select会立刻返回;这用于得到选择的套接字的状态。如果select立刻返回,然后select调用认为是非阻塞的,此时非阻塞调用的标准假设适用。例如,阻塞钩子不会调用,窗体套接字不会退出。

C++网络编程之select的更多相关文章

  1. linux/unix网络编程之 select

    转自http://www.cnblogs.com/zhuwbox/p/4221934.html linux 下的 select 知识点 unp 的第六章已经描述的很清楚,我们这里简单的说下 selec ...

  2. 网络编程之select

    一.select函数简介 select一般用在socket网络编程中,在网络编程的过程中,经常会遇到许多阻塞的函数,网络编程时使用的recv, recvfrom.connect函数都是阻塞的函数,当函 ...

  3. Linux 网络编程之 Select

    /*server*/ #include <stdio.h> #include <string.h> #include <unistd.h> #include < ...

  4. Linux网络编程之select、poll、epoll的比较,以及epoll的水平触发(LT)和边缘触发(ET)

    Linux的网络通信先后推出了select.poll.epoll三种模式. select有以下三个问题: (1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大. ...

  5. python3网络编程之socketserver

    本节主要是讲解python3网络编程之socketserver,在上一节中我们讲到了socket.由于socket无法支持多用户和多并发,于是就有了socket server. socket serv ...

  6. 网络编程之UDP编程

    网络编程之UDP编程 UDP协议是一种不可靠的网络协议,它在通信的2端各建立一个Socket,但是这个Socket之间并没有虚拟链路,这2个Socket只是发送和接受数据的对象,Java提供了Data ...

  7. unix下网络编程之I/O复用(三)

    poll函数 在上文unix下网络编程之I/O复用(二)中已经介绍了select函数的相关使用,本文将介绍另一个常用的I/O复用函数poll.poll提供的功能与select类似,不过在处理流设备时, ...

  8. 高并发网络编程之epoll详解(转载)

    高并发网络编程之epoll详解(转载) 转载自:https://blog.csdn.net/shenya1314/article/details/73691088 在linux 没有实现epoll事件 ...

  9. 网络编程之C10K

    网络编程之C10K 虽然在过去的十几年里C10K问题已经可以很好的解决,但学习网络编程时研究C10K问题仍然价值巨大,因为技术的发展都是有规律和线索可循的,了解C10K问题及其解决思路,通过举一反三, ...

随机推荐

  1. archlinux 安装手记

    Wiki常用软件 https://wiki.archlinux.org/index.php/Common_Applications -> 移动硬盘等的自动挂载 pacman -S gvfs-af ...

  2. 如何修改file控件

    在移动web开发过程中,常常会用到input file这控件,但css不能修改其样式往往让开发者很头疼,直接把他放到页面上又不美观: 下面介绍的方法,可以将该控件的显示样式替换成一个图标:   该方法 ...

  3. ROS的单线程Spinning和多线程Spinning

    单线程Spinning ros::spin()是最简单的单线程自旋, 它会一直调用直到结束 用法:  ros::spin(); 另一个单线程spinning是ros::spinOnce(),它定期调用 ...

  4. Mui框架一 快捷键+基础知识点

    1.折叠面板--mAccordion 2.数字角标-mBadges <h5>有底色</h5> <span class="mui-badge">灰 ...

  5. java 字符串判断是否相等

    在其它编程语言中,判断字符串通常用"=="进行判断,但是在java中由于String类型是一个对象,不能使用"=="进行判断 需要使用equals()方法.

  6. php实现递归的三种方式: 遍历文件夹实例

    递归函数是我们常用到的一类函数,最基本的特点是函数自身调用自身,但必须在调用自身前有条件判断,否则无限无限调用下去.实现递归函数可以采取什么方式呢?本文列出了三种基本方式.理解其原来需要一定的基础知识 ...

  7. 为iOS的mobileconfig文件进行签名

    本文主要讲,使用苹果开发者证书进行签名达到目的,本文两种方法,一种是刀耕火种的一步步操作,一种使用脚本签名 一.导出苹果证书进行签名 1.从钥匙串(keychain)中导出证书 实用工具->钥匙 ...

  8. JavaWeb AJAX

    1.  Asynchronized JavaScript And XML 异步JavaScript和XML,它并不是一门新的语言或技术,实际是几项技术按一定的方式组合在一起共同的协作中发挥各自的作用, ...

  9. IE9以下 placeholder兼容

    //input placeholder兼容!(function ($, doc, win) { $.fn.placeholder = function () { var i = doc.createE ...

  10. Android中日期函数Calendar的一些用法和注意事项

    1.月份获取时加1 Canlendar.MONTH + 1 因为使用的是罗马历,Calendar.MONTH返回的数值不是一年中月份的值,而是当前月份距离第一个月份的差值 如:当前月份为9月份,距离1 ...