IOCP Server: Select

2024-03-01 02:48
文章标签 select server iocp

本文主要是介绍IOCP Server: Select,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

客户端代码:

/** 文件:Select(客户端)* 说明:项目中需包含 Ws2_32.lib,或使用 #pragma comment(lib, "*.lib")*/#include <stdio.h>
#include <WinSock2.h>#define LENGTH 128
#define PORT_NUM 8086
#define MAX_DELAY 3000					// 比简单示例多出的部分
#define EXIT_WITH_MESSAGE(content) \
do \
{ \WSACleanup(); \printf_s(content); \system("pause"); \return EXIT_FAILURE; \
} \
while (FALSE);int main()
{int ret, len;WORD wVersion;							// 网络传输版本WSADATA wsaData;						// WSADATAchar msg[LENGTH];struct sockaddr_in server;				// 服务器信息SOCKET sockClient = INVALID_SOCKET;		// 待创建的套接字/* 比简单示例多出的部分 */struct timeval tv;struct fd_set fdset;wVersion = MAKEWORD(2, 2);ret = WSAStartup(wVersion, &wsaData);	// 初始化 WinSock DLLif (ret != 0){// 告诉用户不能获取可用的 WinSock DLLEXIT_WITH_MESSAGE("WSAStartup Failed, cannot find a usable winsock dll!\n");}if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){// 告诉用户版本不正确EXIT_WITH_MESSAGE("Error version!\n");}sockClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (INVALID_SOCKET == sockClient){// 套接字创建失败EXIT_WITH_MESSAGE("Invalid socket!\n");}server.sin_family = AF_INET;server.sin_port = htons(PORT_NUM);server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");ret = connect(sockClient, (struct sockaddr *)&server, sizeof(struct sockaddr));if (SOCKET_ERROR == ret){// 连接失败closesocket(sockClient);EXIT_WITH_MESSAGE("Connect failed!\n");}do{/* 比简单示例多出的部分 */FD_ZERO(&fdset);FD_SET(sockClient, &fdset);tv.tv_sec = 0;tv.tv_usec = MAX_DELAY;ret = select(0, NULL, &fdset, NULL, &tv);if (ret <= 0){// 选择失败closesocket(sockClient);EXIT_WITH_MESSAGE("Select failed!\n");}else if (!FD_ISSET(sockClient, &fdset)){// 设置失败closesocket(sockClient);EXIT_WITH_MESSAGE("FD isn't set!\n");}printf_s("Your reply: ");
/* 此为测试代码,因为有严格的超时时间限制,如果在最大延时内收不到则认为设备掉线
/		strcpy_s(msg, LENGTH, "Hello, SweetLover!");	*/gets_s(msg, LENGTH);// send 函数将会把消息发送到已连接的套接字上,而 sendto 则是发送到指定套接字上len = strlen(msg) + 1;ret = send(sockClient, msg, len, 0);if (ret < 0 || ret > len){// 发送有误closesocket(sockClient);EXIT_WITH_MESSAGE("Send message error!\n");}if (strcmp(msg, "Quit") == 0)break;/* 比简单示例多出的部分 */FD_ZERO(&fdset);FD_SET(sockClient, &fdset);tv.tv_sec = 0;tv.tv_usec = MAX_DELAY;ret = select(0, &fdset, NULL, NULL, &tv);if (ret <= 0){// 选择失败closesocket(sockClient);EXIT_WITH_MESSAGE("Select failed!\n");}else if (!FD_ISSET(sockClient, &fdset)){// 设置失败closesocket(sockClient);EXIT_WITH_MESSAGE("FD isn't set!\n");}memset(msg, 0, LENGTH);ret = recv(sockClient, msg, LENGTH, 0);if (SOCKET_ERROR == ret){// 接受有误closesocket(sockClient);EXIT_WITH_MESSAGE("Receive message error!\n");}else if (0 == ret){// 连接断开closesocket(sockClient);EXIT_WITH_MESSAGE("The connection closed!\n");}printf_s("Server: %s\n", msg);}while (strcmp(msg, "Quit"));printf_s("Exit connection!\n");closesocket(sockClient);WSACleanup();system("pause");return EXIT_SUCCESS;
}


 

服务器端代码:

/** 文件:Select(服务器端)* 说明:项目中需包含 Ws2_32.lib,或使用 #pragma comment(lib, "*.lib")*/#include <stdio.h>
#include <WinSock2.h>#define LENGTH 128
#define PORT_NUM 8086
#define MAX_DELAY 3000					// 比简单示例多出的部分
#define EXIT_WITH_MESSAGE(content) \
do \
{ \WSACleanup(); \printf_s(content); \system("pause"); \return EXIT_FAILURE; \
} \
while (FALSE);int main()
{int ret, len;WORD wVersion;														// 网络传输版本WSADATA wsaData;													// WSADATAchar msg[LENGTH];struct sockaddr_in server, client;									// 服务器信息,客户端信息SOCKET sockServer = INVALID_SOCKET, sockListener = INVALID_SOCKET;	// 服务器套接字,监听套接字/* 比简单示例多出的部分 */struct timeval tv;struct fd_set fdset;wVersion = MAKEWORD(2, 2);ret = WSAStartup(wVersion, &wsaData);	// 初始化 WinSock DLLif (ret != 0){// 告诉用户不能获取可用的 WinSock DLLEXIT_WITH_MESSAGE("WSAStartup Failed, cannot find a usable winsock dll!\n");}if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){// 告诉用户版本不正确EXIT_WITH_MESSAGE("Error version!\n");}sockListener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (INVALID_SOCKET == sockListener){// 套接字创建失败EXIT_WITH_MESSAGE("Invalid listener socket!\n");}server.sin_family = AF_INET;server.sin_addr.s_addr = INADDR_ANY;server.sin_port = htons(PORT_NUM);ret = bind(sockListener, (struct sockaddr *)&server, sizeof(struct sockaddr_in));if (SOCKET_ERROR == ret){// 绑定端口失败closesocket(sockListener);EXIT_WITH_MESSAGE("Bind error!\n");}ret = listen(sockListener, SOMAXCONN);if (SOCKET_ERROR == ret){// 监听失败closesocket(sockListener);EXIT_WITH_MESSAGE("Listen error!\n");}len = sizeof(struct sockaddr_in);sockServer = accept(sockListener, (struct sockaddr*)&client, &len);if (INVALID_SOCKET == sockServer){// 接收失败closesocket(sockListener);EXIT_WITH_MESSAGE("Accept error!\n");}do{/* 比简单示例多出的部分 */FD_ZERO(&fdset);FD_SET(sockServer, &fdset);tv.tv_sec = 0;tv.tv_usec = MAX_DELAY;ret = select(0, &fdset, NULL, NULL, &tv);if (ret <= 0){// 选择失败closesocket(sockServer);EXIT_WITH_MESSAGE("Select failed!\n");}else if (!FD_ISSET(sockServer, &fdset)){// 设置失败closesocket(sockServer);EXIT_WITH_MESSAGE("FD isn't set!\n");}memset(msg, 0, LENGTH);ret = recv(sockServer, msg, LENGTH, 0);if (SOCKET_ERROR == ret){// 接受有误closesocket(sockServer);EXIT_WITH_MESSAGE("Receive message error!\n");}else if (0 == ret){// 连接断开closesocket(sockServer);EXIT_WITH_MESSAGE("The connection closed!\n");}printf_s("Client: %s\n", msg);/* 比简单示例多出的部分 */FD_ZERO(&fdset);FD_SET(sockServer, &fdset);tv.tv_sec = 0;tv.tv_usec = MAX_DELAY;ret = select(0, NULL, &fdset, NULL, &tv);if (ret <= 0){// 选择失败closesocket(sockServer);EXIT_WITH_MESSAGE("Select failed!\n");}else if (!FD_ISSET(sockServer, &fdset)){// 设置失败closesocket(sockServer);EXIT_WITH_MESSAGE("FD isn't set!\n");}printf_s("Your reply: ");gets_s(msg, LENGTH);len = strlen(msg) + 1;ret = send(sockServer, msg, len, 0);if (ret <= 0 || ret > len){// 发送有误closesocket(sockServer);EXIT_WITH_MESSAGE("Send message error!\n");}}while (TRUE);printf_s("Exit connection!\n");closesocket(sockServer);closesocket(sockListener);WSACleanup();system("pause");return EXIT_SUCCESS;
}


作用:http://baike.baidu.com/subview/621719/11844440.htm?fr=aladdin

1.原型:int select (int maxfd + 1,fd_set *readset,fd_set *writeset, fd_set *exceptset,const struct timeval * timeout);

2.参数:

参数一:最大的文件描述符加1。
参数二:用于检查可读性,
参数三:用于检查可写性,
参数四:用于检查 带外数据,
参数五:一个指向timeval结构的 指针,用于决定select等待I/o的最长时间。如果为空将一直等待。 timeval结构的定义:struct timeval{
long tv_sec; // seconds
long tv_usec; // microseconds
}

总结:

1.编程角度上,Select 的关键就是能否掌握对该函数的使用。

2.Select 中比较重要的结构体是 fd_set 和 timeval,在调用 select 前,要初始化:

FD_ZERO(&fdset);

FD_SET(sockServer, &fdset);

具体阐释:

1.struct fd_set fdset;// 文件(这里的文件指的是套接字 socket)描述集合;

一个文件集合中可以包含多个元素,即:element∈fd_set;

2.FD_ZERO(&fdset); // 初始化文件描述集合为空,没有任何元素

3.FD_SET(sockServer, &fdset);// 将元素放入集合中,可以后置多个

4.详解

函数作用:选择函数确定一个或多个套接字的状态,必要时等待执行同步I / O。

函数参数:

(1)nfds[in]:Windows 下可忽略,只是用于兼容 Berkeley 套接字(Linux、Android)时才会用到。

(2)readfds[in & out]:用于检测可读性的文件描述集合,其他两个是用于检测可写性和异常的文件描述集合。

(3)timeout[in]:最大等待时间。表现为:最大等待时间内,套接字个数检测结果不为空时立刻返回个数,为空则在超时后返回0,错误返回 SOCKET_ERROR。

返回值:三个检测集合中的套接字个数,超时返回0,错误返回 SOCKET_ERROR。

5.小示例:

FD_ZERO(&fd_read);// fd_read.count = 0

FD_SET(s1, &fd_read);// fd_read.count = 1

FD_SET(s2, &fd_read);// fd_read.count = 2

// 在 tv 时间内,服务器的两个套接字 s1 和 s2 只有,s1 来了数据(可读缓冲区不为空)

ret = select(0, &fd_read, NULL, NULL, &tv);// 因此执行后,ret = 1,fd_read.count = 1

if (FD_ISSET(s1, &fd_read)){// recv/recvfrom 接收数据,并且做出处理}// 这里的 if 会被执行

if (FD_ISSET(s2, &fd_read)){// ... }// 这里的 if 不会被执行

同理:如果可写套接字的缓冲区为空,那么检测后就是可写状态

这篇关于IOCP Server: Select的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/760964

相关文章

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

SQL Server清除日志文件ERRORLOG和删除tempdb.mdf

《SQLServer清除日志文件ERRORLOG和删除tempdb.mdf》数据库再使用一段时间后,日志文件会增大,特别是在磁盘容量不足的情况下,更是需要缩减,以下为缩减方法:如果可以停止SQLSe... 目录缩减 ERRORLOG 文件(停止服务后)停止 SQL Server 服务:找到错误日志文件:删除

Windows Server服务器上配置FileZilla后,FTP连接不上?

《WindowsServer服务器上配置FileZilla后,FTP连接不上?》WindowsServer服务器上配置FileZilla后,FTP连接错误和操作超时的问题,应该如何解决?首先,通过... 目录在Windohttp://www.chinasem.cnws防火墙开启的情况下,遇到的错误如下:无法与

一文详解SQL Server如何跟踪自动统计信息更新

《一文详解SQLServer如何跟踪自动统计信息更新》SQLServer数据库中,我们都清楚统计信息对于优化器来说非常重要,所以本文就来和大家简单聊一聊SQLServer如何跟踪自动统计信息更新吧... SQL Server数据库中,我们都清楚统计信息对于优化器来说非常重要。一般情况下,我们会开启"自动更新

JAVA虚拟机中 -D, -X, -XX ,-server参数使用

《JAVA虚拟机中-D,-X,-XX,-server参数使用》本文主要介绍了JAVA虚拟机中-D,-X,-XX,-server参数使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录一、-D参数二、-X参数三、-XX参数总结:在Java开发过程中,对Java虚拟机(JVM)的启动参数进

Windows server服务器使用blat命令行发送邮件

《Windowsserver服务器使用blat命令行发送邮件》在linux平台的命令行下可以使用mail命令来发送邮件,windows平台没有内置的命令,但可以使用开源的blat,其官方主页为ht... 目录下载blatBAT命令行示例备注总结在linux平台的命令行下可以使用mail命令来发送邮件,Win

HTML5中下拉框<select>标签的属性和样式详解

《HTML5中下拉框<select>标签的属性和样式详解》在HTML5中,下拉框(select标签)作为表单的重要组成部分,为用户提供了一个从预定义选项中选择值的方式,本文将深入探讨select标签的... 在html5中,下拉框(<select>标签)作为表单的重要组成部分,为用户提供了一个从预定义选项中

MySQL 中的服务器配置和状态详解(MySQL Server Configuration and Status)

《MySQL中的服务器配置和状态详解(MySQLServerConfigurationandStatus)》MySQL服务器配置和状态设置包括服务器选项、系统变量和状态变量三个方面,可以通过... 目录mysql 之服务器配置和状态1 MySQL 架构和性能优化1.1 服务器配置和状态1.1.1 服务器选项

查询SQL Server数据库服务器IP地址的多种有效方法

《查询SQLServer数据库服务器IP地址的多种有效方法》作为数据库管理员或开发人员,了解如何查询SQLServer数据库服务器的IP地址是一项重要技能,本文将介绍几种简单而有效的方法,帮助你轻松... 目录使用T-SQL查询方法1:使用系统函数方法2:使用系统视图使用SQL Server Configu

SQL Server数据库迁移到MySQL的完整指南

《SQLServer数据库迁移到MySQL的完整指南》在企业应用开发中,数据库迁移是一个常见的需求,随着业务的发展,企业可能会从SQLServer转向MySQL,原因可能是成本、性能、跨平台兼容性等... 目录一、迁移前的准备工作1.1 确定迁移范围1.2 评估兼容性1.3 备份数据二、迁移工具的选择2.1