socket网络编程select使用方法

2023-05-16

文章以及源码均为原创,当然欢迎转载,转载请加说明

server.h

//int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout);
//nfds:select监视的文件句柄数
//readfds:select监视的可读文件句柄集合
//writefds: select监视的可写文件句柄集合
//exceptfds:select监视的异常文件句柄集合
//timeout:超时时间,如果timeout == NULL,无期等待
//返回值:
//0:超时
//SOCKET_ERROR:出错
//大于0:fd个数
//
//FD_ZERO(fd_set *fdset):清空fdset
//FD_SET(int fd, fd_set *fdset):设置监视
//FD_CLR(int fd, fd_set *fdset):清除监视
//FD_ISSET(int fd, fd_set *fdset):检查是否可以读写

#ifndef SERVER_H
#define SERVER_H

#include<iostream>
#include <WS2tcpip.h>
#include <vector>

#pragma comment(lib,"Ws2_32.lib")

#define IPADDRESS   "127.0.0.1"
#define PORT        3300

class CServer
{
public:
	CServer();
	~CServer();

	bool Create(const char* ip, int port);
	void Select();
	void Close();

protected:

private:
	SOCKET m_Listenfd;
	std::vector<SOCKET> m_ClientfdVec;
	fd_set m_ReadSet;
	fd_set m_WriteSet;
	fd_set m_ExceptSet;
};

#endif //SERVER_H

server.cpp

#include"server.h"

CServer::CServer()
{
	m_Listenfd = 0;
	FD_ZERO(&m_ReadSet);
	FD_ZERO(&m_WriteSet);
	FD_ZERO(&m_ExceptSet);
	m_ClientfdVec.clear();
}

CServer::~CServer()
{
	Close();
}

bool CServer::Create(const char* I_Ip, int I_Port)
{
	WORD WVersionRequest = { 0 };
	WSADATA WSaDate = { 0 };
	sockaddr_in ServAddr = { 0 };//服务端地址结构

	//注册协议版本
	WVersionRequest = MAKEWORD(2, 2);
	if (WSAStartup(WVersionRequest, &WSaDate))
	{
		perror("WSAStartup");
		return false;
	}
	printf("WSAStartup ok\n");

	//创建服务端监听socket
	m_Listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (m_Listenfd == SOCKET_ERROR)
	{
		perror("socket");
		return false;
	}
	printf("socket ok\n");

	//设置服务端地址和端口
	ServAddr.sin_family = AF_INET;
	inet_pton(AF_INET, I_Ip, &ServAddr.sin_addr);
	ServAddr.sin_port = htons(I_Port);

	//绑定服务端地址和端口
	if (0 != bind(m_Listenfd, (sockaddr*)&ServAddr, sizeof(ServAddr)))
	{
		perror("bind");
		closesocket(m_Listenfd);
		return false;
	}
	printf("bind ok\n");

	//设置监听
	if (0 != listen(m_Listenfd, 5))
	{
		perror("listen");
		closesocket(m_Listenfd);
		return false;
	}
	printf("listen ok\n");

	return true;
}

void CServer::Select()
{
	SOCKET ClientFd = 0;
	sockaddr_in ClientAddr = { 0 };//客户端地址结构
	TIMEVAL TimeVal;//设置超时等待时间
	TimeVal.tv_sec = 5;
	TimeVal.tv_usec = 0;
	char TempBuf[1024] = "";
	int SockAddrLen = sizeof(sockaddr_in);
	bool CloseFlag = false;
	while (true)
	{
		FD_SET(m_Listenfd, &m_ReadSet);
		for (auto Ite : m_ClientfdVec)
		{
			FD_SET(Ite, &m_ReadSet);
		}
		switch (select(FD_SETSIZE, &m_ReadSet, &m_WriteSet, &m_ExceptSet, &TimeVal))
		{
		case 0:
			printf("超时\n");
			continue;
		case SOCKET_ERROR:
			perror("select");
			continue;
		default:
			if (FD_ISSET(m_Listenfd, &m_ReadSet))
			{
				//接受连接
				ClientFd = accept(m_Listenfd, (sockaddr*)&ClientAddr, &SockAddrLen);
				if (ClientFd == 0)
				{
					perror("accept");
				}
				else
				{
					m_ClientfdVec.push_back(ClientFd);
					printf("客户端%s已连接\n", inet_ntoa(ClientAddr.sin_addr));
				}
			}

			for (auto Ite = m_ClientfdVec.begin(); Ite != m_ClientfdVec.end();)
			{
				if (FD_ISSET(*Ite, &m_ReadSet))
				{
					switch (recv(*Ite, TempBuf, sizeof(TempBuf), 0))
					{
					case 0:
						CloseFlag = true;
						break;
					case SOCKET_ERROR:
						perror("recv");
						CloseFlag = false;
						break;
					default:
						//这里可以开个处理本次消息的新线程,或者用线程池
						std::cout << "接收:" << TempBuf << std::endl;
						FD_SET(*Ite, &m_WriteSet);
						CloseFlag = false;
						break;
					}
				}
				if (FD_ISSET(*Ite, &m_WriteSet))
				{
					strcpy(TempBuf, "servertest");
					if (0 >= send(*Ite, TempBuf, sizeof(TempBuf), 0))
					{
						perror("send");
					}
					else
					{
						printf("发送:%s\n", TempBuf);
						FD_CLR(*Ite, &m_WriteSet);
					}
				}
				if (FD_ISSET(*Ite, &m_ExceptSet))
				{

				}

				if (CloseFlag)
				{
					FD_CLR(*Ite, &m_ReadSet);
					closesocket(*Ite);
					Ite = m_ClientfdVec.erase(Ite);
				}
				else
				{
					Ite++;
				}
			}
		}
	}
}

void CServer::Close()
{
	for (auto Fd : m_ClientfdVec)
	{
		closesocket(Fd);
	}
	m_ClientfdVec.clear();
	closesocket(m_Listenfd);
	WSACleanup();
}

int main()
{
	CServer Server;
	if (Server.Create(IPADDRESS, PORT))
	{
		Server.Select();
		Server.Close();
	}
	system("pause");
	return 0;
}

client.h

#ifndef CLIENT_H
#define CLIENT_H

#include<iostream>
#include <WS2tcpip.h>
#include <vector>
#include <mutex>
#include<conio.h>
#include <string.h>
#include <thread>

#pragma comment(lib,"Ws2_32.lib")

#define IPADDRESS   "127.0.0.1"
#define PORT        3300

class CClient
{
public:
	CClient();
	~CClient();

	bool Create(const char* ip, int port);
	void Select();
	void Close();

protected:

private:
	void GetSendBufHandle();

	SOCKET m_Clientfd;
	fd_set m_ReadSet;
	fd_set m_WriteSet;
	fd_set m_ExceptSet;
	std::mutex m_Mutex;
	std::string m_SendBuf;
	bool m_IsStart;
	std::thread *m_pThread;
};

#endif // !CLIENT_H

client.cpp

#include"client.h"

CClient::CClient()
{
	m_Clientfd = 0;
	FD_ZERO(&m_ReadSet);
	FD_ZERO(&m_WriteSet);
	FD_ZERO(&m_ExceptSet);
	m_IsStart = false;
	m_pThread = nullptr;
}

CClient::~CClient()
{
	Close();
}

bool CClient::Create(const char* ip, int port)
{
	WORD WVersionRequest = { 0 };
	WSADATA WSaDate = { 0 };
	sockaddr_in ServAddr = { 0 };

	//注册协议版本
	WVersionRequest = MAKEWORD(2, 2);
	if (0 != WSAStartup(WVersionRequest, &WSaDate))
	{
		perror("WSAStartup");
		return false;
	}
	printf("WSAStartup ok\n");

	//初始化socket
	m_Clientfd = socket(AF_INET, SOCK_STREAM, 0);
	if (m_Clientfd == SOCKET_ERROR)
	{
		perror("socket");
		return false;
	}
	printf("socket ok\n");

	//设置服务器端地址信息
	ServAddr.sin_family = AF_INET;
	inet_pton(AF_INET, ip, &ServAddr.sin_addr);
	ServAddr.sin_port = htons(port);

	//向服务器端发起连接
	if (0 != connect(m_Clientfd, (sockaddr*)&ServAddr, sizeof(ServAddr)))
	{
		perror("connect");
		closesocket(m_Clientfd);
		return false;
	}
	printf("connect ok\n");
	FD_SET(m_Clientfd, &m_ReadSet);
	m_IsStart = true;
	m_pThread = new std::thread(&CClient::GetSendBufHandle, this);
	return true;
}

void CClient::Select()
{
	TIMEVAL TimeVal;//设置超时等待时间
	TimeVal.tv_sec = 5;
	TimeVal.tv_usec = 0;
	char TempBuf[1024] = "";
	std::unique_lock<std::mutex> UniLock(m_Mutex);

	while (true)
	{
		UniLock.unlock();
		FD_SET(m_Clientfd, &m_ReadSet);
		UniLock.lock();
		switch (select(FD_SETSIZE, &m_ReadSet, &m_WriteSet, &m_ExceptSet, &TimeVal))
		{
		case 0:
			printf("超时\n");
			continue;
		case SOCKET_ERROR:
			perror("select");
			continue;
		default:
			if (FD_ISSET(m_Clientfd, &m_ReadSet))
			{
				switch (recv(m_Clientfd, TempBuf, sizeof(TempBuf), 0))
				{
				case 0:
					FD_CLR(m_Clientfd, &m_ReadSet);
					return;
				case SOCKET_ERROR:
					perror("recv");
					break;
				default:
					std::cout << "server:" << TempBuf << std::endl;
					break;
				}
			}

			if (FD_ISSET(m_Clientfd, &m_WriteSet))
			{
				if (0 >= send(m_Clientfd, m_SendBuf.c_str(), 1024, 0))
				{
					perror("send");
				}
				else
				{
					printf("发送:%s\n", m_SendBuf.c_str());
					FD_CLR(m_Clientfd, &m_WriteSet);
				}
			}

			if (FD_ISSET(m_Clientfd, &m_ExceptSet))
			{

			}
			break;
		}
	}
}

void CClient::Close()
{
	closesocket(m_Clientfd);
	WSACleanup();
	m_IsStart = false;
	std::cout << "按回车" << std::endl;
	m_pThread->join();
	delete m_pThread;
}

void CClient::GetSendBufHandle()
{
	char TempBuf[1024] = { 0 };
	std::unique_lock<std::mutex> UniLock(m_Mutex);
	UniLock.unlock();
	while (m_IsStart)
	{
		std::cin >> TempBuf;
		UniLock.lock();
		m_SendBuf = TempBuf;
		FD_SET(m_Clientfd, &m_WriteSet);
		UniLock.unlock();
	}
}

int main()
{
	CClient Client;
	if (Client.Create(IPADDRESS, PORT))
	{
		Client.Select();
		Client.Close();
	}
	system("pause");
	return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

socket网络编程select使用方法 的相关文章

  • URL转义及编码

    js对文字进行编码涉及3个函数 xff1a escape encodeURI encodeURIComponent xff0c 相应3个解码函数 xff1a unescape decodeURI decodeURIComponent url
  • 从C到C++高级过渡

    当做速学笔记使用 简写 基础篇 环境设置 g 43 43 有些系统默认是使用 C 43 43 98 xff0c 我们可以指定使用 C 43 43 11 来编译 main cpp 文件 xff1a g span class token ope
  • 收藏!了解UART总线工作原理看这一篇就够了!

    原文 xff1a 玩转单片机 2019 08 24 16 50 29 越学到后面 xff0c 基础知识更加不能忘记 xff0c 温故而知新 还记得当年的打印机 xff0c 鼠标和调制解调器吗 xff1f 他们都有巨大笨重的连接器和粗电缆 x
  • extern "C"在DLL导出函数时有什么作用?

    extern是c c 43 43 语言中表明函数和全局变量作用范围的关键字 该关键字告诉编译器 xff0c 其声明的函数和变量可以在本模块或其他模块中使用 通常 xff0c 在模块的头文件中对本模块提供给其他模块引用的函数和全局变量以关键字
  • MPU6050六轴传感器的原理及编程说明

    一 xff0e 简介 MPU6050 是 InvenSense 公司推出的整合性 6 轴运动处理组件 xff0c 其内部整合了 3 轴陀螺仪和 3 轴加速度传感器 xff0c 并且含有一个IIC 接口 xff0c 可用于连接外部磁力传感器
  • mysql-mysqlbinlog的使用详解

    一 背景 二进制日志在MySQL数据库中有着至关重要的作用 xff0c 而读取二进制日志的工具就显得同样重要了 xff0c 官方的mysqlbinlog就是读取二进制日志的工具 xff0c 这里就结合官网和自己的实践整理一下 xff08 P
  • mongo-db相关方法

    一 参数 名称 描述 db adminCommand 针对 admin数据库运行命令 db aggregate 运行不需要基础集合的管理 诊断管道 db cloneDatabase hostname 不推荐使用 当针对MongoDB 4 0
  • Django-django.core.exceptions.ImproperlyConfigured: SQLite 3.9.0 or later is required (found 3.7.17)

    运行Django报错 xff0c 原因是因为SQLite版本过低 xff0c 需要升级 下载源码包 xff1a wget https www sqlite org 2021 sqlite autoconf 3350500 tar gz xf
  • TIDB-Error 1105: Out Of Memory Quota问题解决

    一 背景 复杂sql查询报错 二 原因 单条s q l使用内存默认为1G 三 解决 tiup cluster edit config tidb test server configs tidb mem quota query 4294967
  • Kafka-offset链接kafka链接不上

    是在kafka的broker配置server properties的listeners改为listeners 61 PLAINTEXT kafka ip 9092 kafka ip要写具体IP xff0c 不要写localhost
  • python-加密解密

    一 安装对应的库 pip span class token function install span pycryptodome 二 加密和解密的步骤 span class token comment 加密 span def cry pas
  • Js闭包理解、运用

    br onClick function br var pageNum 61 sourcePageNum br return function node br getChildSources node pageNum br pageNum 6
  • 关于C++ 的无名对象

    include lt iostream gt using namespace std class A public explicit A int val m val val cout lt lt 34 call 1 34 lt lt end
  • pt工具的使用(7) pt-archiver的使用

    一 描述 pt archiver 是归档表的工具 xff0c 在 sql 中写入高效归档和清除作业 目标是在不对 OLTP 查询产生太大影响的情况下 xff0c 将旧数据从表中蚕食掉 xff0c 从而实现低影响 仅向前的作业 您可以将数据插
  • linux-node_exporter突然挂掉(couldn‘t get dbus connection)

    一 背景 突然收到一台机器挂掉的告警 xff0c 去上面查看发现机器正常 xff0c uptime正常 xff0c 没有重启情况 xff0c UID 20029的用户是tidb su tidb的时间较长 xff0c node exporte
  • pt工具的使用(1) pt工具的安装

    PT工具是使用Perl语言编写和执行的 xff0c 所以需要系统中有Perl环境 rpm qa perl DBI perl DBD MySQL perl Time HiRes perl IO Socket SSL 检查是否已经安装pt工具所
  • 使用move_base进行路径规划

    本文所实现的效果来自 ROS入门实例 xff0c 对初学者会有一定帮助 move base是ROS环境下一个重要的功能包 xff0c 可以使机器人在指定框架内移动到目标位置 xff0c 是实现后续导航功能的基础 xff0c 很多人想学习gm
  • iperf3-带宽测试工具的详细使用说明

    软件简介 xff1a iperf3 是一个 TCP UDP 和 SCTP 网络带宽测量工具 是用于主动测量 IP 网络上可达到的最大带宽的工具 它支持调整与时序 xff0c 协议和缓冲区有关的各种参数 对于每个测试 xff0c 它都会报告测
  • 用示波器 查看波特率是多少?

    在做涉及串口操作的应用时 xff0c 要看看串口数据是否正常 xff0c 如果串口通信有问题 xff0c 也可以用示波器来诊断 示波器可以通过高低电平来检测哪里有数据 xff0c 哪里没数据 xff0c 判断哪个模块出问题了 示波器具体用法
  • VS C++ 实现发布订阅模式(Publish/Subscribe)——基于旧版PX4 uORB模式

    源码已经上传至我的 span class token punctuation span Gitee span class token punctuation span span class token punctuation span ht

随机推荐

  • 【TCP专题】TCP连接建立

    今天开始 xff0c 我们整理一些关于TCP协议的知识 这块的内容写起来是非常费劲的 xff0c 因为本身TCP协议就不是一个简单的协议 xff0c 它能获得如今的地位 xff0c 和其复杂且出色的表现是分不开的 什么是面向连接 众所周知
  • cmake中添加引用动态链接和静态链接库

    动态库的添加 xff1a span class hljs keyword link directories span span class hljs envvar PROJECT SOURCE DIR span lib span class
  • ESP32的SDK开发之blufi一键配网

    ESP32 是集成 2 4 GHz Wi Fi 和蓝牙双模的单芯片方案 xff0c 采用台积电 TSMC 超低功耗的 40 纳米工艺 xff0c 拥有最 佳的功耗性能 射频性能 稳定性 通用性和可靠性 xff0c 适用于各种应用和不同功耗需
  • javascript作用域链的灵活运用1

    size 61 large javascript比较出彩的运用之一 xff1a 作用域链 1 对于有洁癖的前台人员来说 xff0c 全局变量就像长在美女脸上的黑斑 xff0c 真的无法容忍 2 javascript权威指南 说的那样 xff
  • ESP32的SDK开发之blufi一键配网微信小程序端开发

    上一篇文章简单介绍了blufi配网协议 xff0c 现在来讲讲再微信小程序端实现配网的控制 xff0c 小程序开发是基于官方原生API开发 本人的微信小程序开发也是初学的 xff0c 由于之前没接触过前端开发 xff0c 软件写的很渣渣 蓝
  • 自定义View之渐变色圆形进度条

    先展示下效果图 xff1a 然后按照自定义view的步骤来实现 我们需要将目标定义清楚 xff1a 目标是渐变色圆形进度条 xff0c 那么 xff0c 使用canvas画弧形是基础了 xff0c 另外是渐变色的效果 xff0c 这里使用L
  • NEMA协议解析 (GPS标准协议)

    概述 NMEA是National Marine Electronics Association 的缩写 xff0c 是美国国家海洋电子协会的简称 xff0c 现在是GPS导航设备统一的RTCM标准协议 协议集合 NMEA 0183协议定义的
  • 深入分析websocket协议,从3个方面设计网络应用层协议丨网络编程|网络IO|epoll|socket|网络协议丨c/c++linux服务器开发

    深入分析websocket协议 xff0c 从3个方面设计网络应用层协议 视频讲解如下 xff1a 深入分析websocket协议 xff0c 从3个方面设计网络应用层协议丨网络编程 网络IO epoll socket 网络协议丨c c 4
  • CMake找不到opencv库解决办法

    一 问题详情 在ubuntu中使用CMake编译链接opencv库的程序时FIND PACKAGE OpenCV REQUIRED 报错 xff0c 找不到opencv xff0c 信息如下 xff1a Found OpenCV Windo
  • 详解使用PHP CURL访问HTTPS

    三年前写过一篇 一个简陋的支持HTTPS的PHP CURL封装函数 xff0c 当时只是知其然不知其所以然 xff0c 今天来详细梳理一下 为方便说明 xff0c 先上代码吧 这是今天重新封装的一个函数 curl POST 64 param
  • adb启动Android系统设置命令

    adb打开系统设置的命令 adb命令打开手机设置页面 设置主页面 adb shell am start com android settings com android settings Settings 安全 adb shell am s
  • bootjar和fw配合动态jar

    Gradle 43 bootJar打包SpringBoot工程并分离jar包和配置文件 ruiurrui的博客 CSDN博客 bootjar Gradle 43 bootJar打包SpringBoot工程并分离jar包和配置文件 ruiur
  • 解决 Ubuntu 无法播放 MP4 格式视频的问题的办法

    解决 Ubuntu22 04 无法播放 MP4 格式视频的问题的办法 问题原因 xff1a 系统中的终端上安装缺少的编解码器 解决办法 xff1a 第一条命令将更新存储库 xff1a sudo apt get update 安装以下包含视频
  • 程序查询方式、程序中断、直接内存存取DMA

    程序查询方式 xff1a 当主机进行I O操作时 xff0c 首先发出询问信号 xff0c 读取设备的状态并根据设备状态决定下一步操作究竟是进行数据传输还是等待 这种控制下 xff0c CPU一旦启动I O xff0c 必须停止现行程序的运
  • app监听白天黑夜

    需要在AndroidManifest中的MainActivity配置 xff1a android configChanges 61 34 uiMode 34 64 param newConfig 64 Override public voi
  • 可缩放性ImageView(可以放大缩小)

    由于项目需求的原因 xff0c 最近一直在研究可缩放性ImageView xff0c 用本文来记录一下最近所学 xff1a 该ImageView的实现功能有 xff1a 1 xff09 初步打开时 xff0c 图片按比例满屏 xff08 填
  • 两行代码用camera2 打开闪光灯

    CameraManager c 61 CameraManager getSystemService Context CAMERA SERVICE c setTorchMode c getCameraList 0 true 打开闪光灯 c s
  • 混淆与加固

    https blog csdn net guolipeng network article details 74551968 上面是混淆 加固方面 腾讯乐固首选 xff0c 阿里加固没毛用 xff0c 360次选 原本大小阿里聚安全腾讯云应
  • C语言10进制转16进制

    void decimal to hexaDecimal int a char strs char hex int i 61 0 int j 61 0 int base 61 16 char tmp 16 while a gt 0 j 61
  • socket网络编程select使用方法

    文章以及源码均为原创 xff0c 当然欢迎转载 xff0c 转载请加说明 server h int select int nfds fd set readfds fd set writefds fd set exceptfds const