windows socket编程select模型使用

int select(

int nfds,            //忽略

fd_ser* readfds,    //指向一个套接字集合,用来检测其可读性

fd_set* writefds,   // 指向一个套接字结合,用来检测其可写性

fd_ser* exceptfds, //指向一个套接字集合,用来检测错误

const struct timeval * timeout   //指定此函数等待的最长时间,如果为NULL,则最长时间为无限大。

);

参数说明:

(1)   nfds  windows下未使用,linux下会使用此参数

(2)   readfds:   readfds集合中的套接字发送在以下三种情况中任意一种就会被视为可读,select函数返回后继续留在readfds集合中,不可读的会被移除readfds集合。

1.套接字有数据可读,可以对套接字调用recv函数接收数据

2.套接字的连接已经关闭,重启或者中断,此时应该对套接字进行关闭

3.listen被调用,并且有一个连接未决,对 listen套接字调用accept函数建立新的链接。

(3)   writefds:    readfds集合中的套接字在以下三种情况下会被视为可写

1.使用connect套接字首次建立链接

2.使用accept套接字被接收

3.使用send操作失败,返回WSAEWOULDBLOCK错误,而且缓冲区的空间变得可用

send出去的数据其实都先存在winsock的发送缓冲区中,然后才发送出去,如果缓冲区满了,那么再调用send(WSASend,sendto,WSASendTo)的话,就会返回一个 WSAEWOULDBLOCK的错误码,接下来随着发送缓冲区中的数据被发送出去,缓冲区中出现可用空间时,一个 FD_WRITE 事件才会被触发,这里比较容易混淆的是 FD_WRITE 触发的前提是 缓冲区要先被充满然后随着数据的发送又出现可用空间,而不是缓冲区中有可用空间

(4)   exceptfds   (未使用过,没有进行深入的研究)

1.如果一个非阻塞连接调用正在被处理,连接视图失败

2.OOB数据可读

(5)   timeout:   设置时间,如果超过设定时间,还没有网络事件发生,则返回0,如果此参数为NULL,select会无限等待,直到有一个描述字满足条件。

timeout指向一个timeval结构

typedef struct timeval

{

long tv_sec;       //只是等待多少秒

long tv_usec;     //指示等待多少毫秒

} timeval;

如果timeval为{0,0},则select()立即返回,这可用于探询所

选套接口的状态。如果处于这种状态,则select()调用可认为是非阻塞的,且一切适用于非阻塞调用的假设都适用于它

具体编程流程

1.初始化套接字集合fdSocket,向这个集合添加监听套接字

2.将fdSocket集合拷贝到fdRead传递给select函数,当有时间发送时,select函数移除fdRead集合中没有未决io操作的套接字

3.比较原来fdSocket集合与select处理后的fdRead集合。确定哪些套接字有未决IO

4.回到第2步继续处理

	my_socket();
	my_bind(port);
	my_listen();

	//PostMessage(h_hand,WM_USER_THREADEND,0,0);

	//select模型处理过程
	//(1).初始化套接字集合fdSocket.添加监听套接字句柄到这个集合
	FD_ZERO(&fdSocket);
	FD_SET(sSock,&fdSocket);

	while (1)
	{

		//(2.)将fdSocket集合的一个拷贝fdRead传递给select函数
		//当有时间发生时,select函数一处fdRead集合中没有未决IO操作的套接字句柄,然后返回。
		fd_set fdRead = fdSocket;
		int nRet = select(0,&fdRead,NULL,NULL,NULL);    //timeout参数控制select()完成的时间。若timeout参数为空指针,则select()将一直阻塞
														//到有一个描述字满足条件。否则的话,timeout指向一个timeval结构,其中指定了select()
														//调用在返回前等待多长时间
														//fdwrite  1. 接成功的套接字  在第一次建立连接时,C/S端都会触发一个FD_WRITE事件
																//2, 触发的前提是 缓冲区要先被充满然后随着数据的发送又出现可用空间

		if(nRet>0)
		{
			//(3)通过原来的fdSocket集合与select处理后的fdRead集合比较
			//确定哪些套接字有未决io,并进一步处理这些io
			for(int i=0;i<(int)fdSocket.fd_count;i++)
			{
				if(FD_ISSET(fdSocket.fd_array[i],&fdRead))
				{
					if(fdSocket.fd_array[i] == sSock)   //(1)监听套接字收到新连接,有新的链接
					{
						if(fdSocket.fd_count<FD_SETSIZE)   //判断集合满了吗?
						{

							int socke_len = sizeof(remoteAddr);

							//4.accept
							SOCKET cSock = accept(sSock,(SOCKADDR*)&remoteAddr,&socke_len);

							if(cSock == INVALID_SOCKET)
							{
								AfxMessageBox("accept failed!\n");
								printf("accept failed!\n");
								continue;
							}
							FD_SET(cSock,&fdSocket);

							//printf("接收到一个连接请求!:%s\r\n",inet_ntoa(remoteAddr.sin_addr) );
							//printf("当前连接到服务器的客户端有 %d 个\n",fdSocket.fd_count+1);
							socket_id = cSock*(-1);

							PostMessage(h_hand,WM_USER_THREADEND,0,0);

						}
						else
						{
							AfxMessageBox("too much connections !\n");
							printf("too much connections \n");
							continue;
						}

					}
					else
					{

						int nRecv = recv(fdSocket.fd_array[i],readText,sizeof(readText),0);
						socket_id = fdSocket.fd_array[i];
						if(nRecv>0)    //(2)可读
						{
							readText[nRecv] = ‘\0‘;

							//HWND   g_WindowHandle=((CDialog *)AfxGetMainWnd())->GetSafeHwnd();

							PostMessage(h_hand,WM_USER_THREADEND,0,0);
						}
						else           //(3)连接关闭,重启或中断
						{
							closesocket(fdSocket.fd_array[i]);
							FD_CLR(fdSocket.fd_array[i],&fdSocket);
							someone_out = TRUE;
							PostMessage(h_hand,WM_USER_THREADEND,0,0);
						}
					}
				}

			}

		}
		else
		{
			AfxMessageBox("failed select()]n");
			printf("failed select()]n");
			break;

		}

	}

以上只是我在项目中使用的部分代码,最开始的my_socket,my_bind,my_listen都是自己对socket,bind,listen自己重新做的封装

时间: 2024-08-29 06:30:09

windows socket编程select模型使用的相关文章

Windows Socket编程示例-TCP示例程序

前面一部分是介绍,后面有示例 1.网络中进程之间如何通信? 首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的.其实TCP/IP协议族已经帮我们解决了这个问题,网络层的"ip地址"可以唯一标识网络中的主机,而传输层的"协议+端口"可以唯一标识主机中的应用程序(进程).这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互. 使用TCP

Windows Socket编程--ip地址转换

在Windows Socket编程中,需要将ip地址在网络字节顺序与主机字节顺序之间进行转换,该过程的代码如下: 1 #include <Winsock2.h> 2 #include <Ws2tcpip.h> //为了使用inet_pton()和inet_ntop()函数 3 #include <iostream> 4 5 #pragma comment(lib,"ws2_32.lib") //socket编程需要引用该库 6 7 using std

【windows socket编程+服务器客户端】

Windows Socket编程与服务器客户端示例 Winsock是 Windows下套接字标准. Socket套接字基于计算机网络,提供同一系统上不同进程或由局域网连接在一起的不同机器上的进程间通讯功能.如下图: 套接字通过IP地址,Port端口号标识,通过这个标识可以在整个局域网定位一个套接字,通过套接字进程便可以相互传输数据.如:进程A与进程B之间欲通过套接字通信,首先进程A创建一个有IP地址,端口号唯一标识的套接字,进程B同样创建一个有IP地址,端口号唯一标识的套接字,进程A,B便可以通

Windows Socket 编程_单个服务器对多个客户端简单通讯

单个服务器对多个客户端程序: 一.简要说明 二.查看效果 三.编写思路 四.程序源代码 五.存在问题 一.简要说明: 程序名为:TcpSocketOneServerToMulClient 程序功能:实现单个服务器对多个客户端通讯功能的小程序. PS: 这是继上次简单的 Tcp Windows Socket 编程后的再一程序,程序实现依然不是很严谨,还待完善~ 二.查看效果: 三.编写思路: 由上一次的程序思路来看,如果想实现单个服务器对多个客户端程序的通讯的话,这次程序编写尝试从多线程的角度来考

Windows Socket I/O模型

老陈有一个在外地工作的女儿,不能经常回来,老陈和她通过信件联系.他们的信会被邮递员投递到他们的信箱里.这和Socket模型非常类似.下面我就以老陈接收信件为例讲解Socket I/O模型~~~ 一:select模型 老陈非常想看到女儿的信.以至于他每隔10分钟就下楼检查信箱,看是否有女儿的信~~~~~在这种情况下,"下楼检查信箱"然后回到楼上耽误了老陈太多的时间,以至于老陈无法做其他工作.select模型和老陈的这种情况非常相似:周而复始地去检查......如果有数据......接收/

UNIX网络编程-Select模型学习

1.相关接口介绍 1.1 select ---------------------------------------------------------------------- #include <sys/select.h> #include <sys/time.h> int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeou

网络编程(windows socket编程)

TCP服务器端代码: 1 // TcpSrv.cpp: 定义控制台应用程序的入口点. 2 // 3 4 #include "stdafx.h" 5 #include<Windows.h> 6 #pragma comment(lib,"ws2_32.lib") 7 8 int main() 9 { 10 //************加载套接字库***************** 11 WORD wVersionRequested; 12 WSADATA w

Windows Socket 编程_ 简单的服务器/客户端程序

转载自:http://blog.csdn.net/neicole/article/details/7459021 一.程序运行效果图 二.程序源代码 三.程序设计相关基础知识 1.计算机网络    2.IP地址    3.协议    4.网络体系结构    5.TCP/IP体系结构与特点    6.客户机/服务器模式    7.TCP/IP特点    8.套接字的引入    9.面向 连接/无连接 的套接字的系统调用时序图/流程图 一.程序运行效果图 二.程序源代码 [cpp] view pla

Windows Socket 编程:TCP服务器端

#include <stdio.h> #include <stdlib.h> #include <winsock2.h> int main(int argc,char* argv[]) { int szClntAddr; char message[] = "hello szt!~\n"; WSADATA wsaData; SOCKET hServSock,hClntSock; SOCKADDR_IN servAddr,clntAddr; WSASta