socket通信之select

news2024/12/24 20:52:56

多线程版本的的socket的server端

#include "socket.hpp"
#include <iostream>
#include <string>
#include <memory>

DWORD WINAPI threadProc(LPVOID lp)
{
	SOCKET sClient = *(SOCKET*)(lp);
	while (true) {
		char buff[1024] = { 0 };
		int result = recv(sClient, buff, 1024, 0);
		if (result > 0) {
			std::cout << "接收到了数据" << buff << std::endl;
		}
		else
		{
			std::cout << "客户端断开连接" << std::endl;
			closesocket(sClient);
			break;
		}
	}
	//closesocket(sClient);
	return NULL;
}

int main()
{
	SocketInit socketInit;

	//创建监听套接字
	SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sListen == SOCKET_ERROR)
	{
		std::cout << "监听失败" << std::endl;
	}
	//绑定套接字
	sockaddr_in sock_in;
	sock_in.sin_family = AF_INET;
	sock_in.sin_port = htons(1234);
	sock_in.sin_addr.S_un.S_addr = INADDR_ANY;
	int ret = bind(sListen, (sockaddr*)(&sock_in), sizeof(sock_in));
	if (ret == SOCKET_ERROR)
	{
		std::cout << "绑定套接字失败" << std::endl;
		closesocket(sListen);
		return -1;
	}
	//
	if (listen(sListen, 10) == SOCKET_ERROR)
	{
		std::cout << "监听失败" << std::endl;
		return -1;
	}
	sockaddr_in sock_client;
	int nlen = sizeof(sockaddr_in);
	while (true)
	{
		//接受客户端的连接
		SOCKET sClient = accept(sListen, (sockaddr*)(&sock_client), &nlen);
		if (sClient == SOCKET_ERROR)
		{
			std::cout << "接收客户端失败" << std::endl;
			closesocket(sListen);
			return -1;
		}
		std::cout << "与客户端连接成功...." << std::endl;
		CreateThread(NULL, 0, threadProc, (LPVOID*)(&sClient), NULL, NULL);
	}

	closesocket(sListen);
	getchar();
	return 0;
}

poll和epoll只能在linux环境下适用

select模型 代码

#define _WINSOCK_DEPRECATED_NO_WARNINGS


/*
select是一个I/O多路复用的系统调用函数,主要用于处理多个文件描述符的读写操作。
它常常被用于网络编程中,可以同时监听多个文件描述符的状态变化,从而实现高并发的网络通信。
以下是一个在Windows平台上使用select模型的demo代码:
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>

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

#define BUF_SIZE 1024
#define PORT 1234

int main() {
	// 初始化Winsock2库
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		printf("WSAStartup() failed!\n");
		exit(EXIT_FAILURE);
	}

	// 创建Socket套接字
	SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, 0);
	if (listen_sock == INVALID_SOCKET) {
		printf("socket() failed: %d\n", WSAGetLastError());
		exit(EXIT_FAILURE);
	}

	// 绑定到本地端口
	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);

	if (bind(listen_sock, (sockaddr*)&addr, sizeof(addr)) < 0) {
		printf("bind() failed: %d\n", WSAGetLastError());
		exit(EXIT_FAILURE);
	}

	// 监听端口
	if (listen(listen_sock, SOMAXCONN) < 0) {
		printf("listen() failed: %d\n", WSAGetLastError());
		exit(EXIT_FAILURE);
	}

	fd_set read_fds, tmp_fds;
	FD_ZERO(&read_fds);
	FD_SET(listen_sock, &read_fds);

	printf("Server listening on port %d...\n", PORT);

	while (1) {
		tmp_fds = read_fds;

		// 多路复用I/O
		if (select(0, &tmp_fds, NULL, NULL, NULL) < 0) {
			printf("select() failed: %d\n", WSAGetLastError());
			exit(EXIT_FAILURE);
		}

		// 检查所有Socket文件描述符是否有可读事件
		for (int i = 0; i < tmp_fds.fd_count; ++i) {
			SOCKET sock = tmp_fds.fd_array[i];

			// 如果有新的连接请求,接受并将新连接加入文件描述符集合
			if (sock == listen_sock && FD_ISSET(listen_sock, &tmp_fds)) {
				sockaddr_in clnt_addr;
				int clnt_len = sizeof(clnt_addr);
				SOCKET clnt_sock = accept(listen_sock, (sockaddr*)&clnt_addr, &clnt_len);
				if (clnt_sock == INVALID_SOCKET) {
					printf("accept() failed: %d\n", WSAGetLastError());
					continue;
				}

				FD_SET(clnt_sock, &read_fds);
				printf("New client connected: %s\n", inet_ntoa(clnt_addr.sin_addr));

				// 如果是已连接的Socket,读取并处理数据
			}
			else {
				char buf[BUF_SIZE] = { 0 };
				int recv_len = recv(sock, buf, BUF_SIZE, 0);
				if (recv_len <= 0) {
					printf("Socket closed: %d\n", sock);
					closesocket(sock);
					FD_CLR(sock, &read_fds);
				}
				else {
					printf("Received message from client[%d]: %s\n", sock, buf);
					send(sock, buf, recv_len, 0);
				}
			}
		}
	}

	closesocket(listen_sock);
	WSACleanup();

	return 0;
}

/*
这个demo实现了一个简单的TCP服务器,使用select

百宝箱助理 :
模型处理多个客户端的连接请求和数据读写操作。
其中主要的代码是在while循环中的select调用和对文件描述符事件的处理逻辑。
通过多路复用的方式,我们可以检查多个文件描述符的状态,并实现有限资源下的高并发网络通信。
*/

window平台多线程实现客户端收发数据分离

/*
以下是 Windows 平台下用多线程实现 Socket 客户端收发数据分离的示例代码:
*/
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#include <process.h>
#pragma comment(lib, "ws2_32.lib")
#define BUF_SIZE 1024
#define PORT 1234

// 子线程函数:接收服务端发来的数据并输出到控制台
unsigned __stdcall recv_thread(void* arg) {
	SOCKET sock = *(SOCKET*)arg;
	char buf[BUF_SIZE] = { 0 };
	int recv_len = 0;

	while ((recv_len = recv(sock, buf, BUF_SIZE, 0)) > 0) {
		printf("Received message from server: %s\n", buf);
		memset(buf, 0, sizeof(buf));
	}

	printf("Connection closed by server.\n");
		return 0;
}

int main() {
	// 初始化 Winsock2 库
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		printf("WSAStartup() failed!\n");
		exit(EXIT_FAILURE);
	}

	// 创建 Socket 套接字
	SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock == INVALID_SOCKET) {
		printf("socket() failed: %d\n", WSAGetLastError());
		exit(EXIT_FAILURE);
	}

	// 连接服务端
	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
		if (connect(sock, (const sockaddr*)&addr, sizeof(addr)) < 0) {
			printf("connect() failed: %d\n", WSAGetLastError());
			exit(EXIT_FAILURE);
		}

	// 创建子线程用于接收数据
	HANDLE recv_hThread = (HANDLE)_beginthreadex(NULL, 0, &recv_thread, &sock, 0, NULL);
	if (recv_hThread == NULL) {
		printf("Create thread failed: %d\n", GetLastError());
		exit(EXIT_FAILURE);
	}

	// 主线程用于发送数据
	char buf[BUF_SIZE] = { 0 };
	printf("Please enter messages to send (input 'quit' to exit):\n");
	while (fgets(buf, BUF_SIZE, stdin) != NULL) {
		if(strcmp(buf, "quit\n") == 0) {
			printf("Quit.\n");
			break;
		}

		send(sock, buf, strlen(buf), 0);
		memset(buf, 0, sizeof(buf));
	}

	// 等待子线程结束并释放资源
	WaitForSingleObject(recv_hThread, INFINITE);
	CloseHandle(recv_hThread);
	closesocket(sock);
	WSACleanup();
	return 0;
}
/*
在本示例中,我们启动了一个子线程用于接收服务端的数据,
并将主线程用于发送数据。子线程在接收到数据后将数据输出到控制台,
而主线程则从标准输入中读取数据并发送给服务端。这样就达到了收发数据分离的目的,
主线程在输入数据时不会被阻塞,程序可以更加流畅地运行。
*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/472818.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构初阶 —— 树(堆)

目录 一&#xff0c;堆 堆的概念 向下调整法&#xff08;数组&#xff09; 向上调整法&#xff08;数组&#xff09; 堆的创建&#xff08;建堆&#xff09; 堆的实现 一&#xff0c;堆 堆的概念 如有个关键码的集合K{&#xff0c;&#xff0c;&#xff0c;...&#xf…

Anaconda你不得不知道的若干知识点

Anaconda你不得不知道的若干知识点 1. 查看所有的环境变量2. 加载tensorflow在jupyter中会挂掉怎么办&#xff1f;3. Excel xlsx file&#xff1b; not supported两种解决办法4. (unicode error)5. 统计pandas二维表中的某列的重复值法一&#xff1a;df.loc[:,col_name].value_…

Fabric测试与基础

Fabric官网:Introduction — hyperledger-fabricdocs main documentation 1.测试网络 ./network.sh up #启动./network.sh down #关闭 2.Fabric核心模块 peer:主节点模块&#xff0c;负责存储区块链数据&#xff0c;运行维护链码 orderer:交易打包、排序模块 cryptogen:组织…

【机器学习分支】重要性采样(Importance sampling)学习笔记

重要性采样&#xff08;importance sampling&#xff09;是一种用于估计概率密度函数期望值的常用蒙特卡罗积分方法。其基本思想是利用一个已知的概率密度函数来生成样本&#xff0c;从而近似计算另一个概率密度函数的期望值。 想从复杂概率分布中采样的一个主要原因是能够使用…

uniapp 抖音授权登录、发布、分享 Ba-Aweme

简介&#xff08;下载地址&#xff09; Ba-Aweme 是一个集成抖音的uniapp插件&#xff0c;支持抖音授权登录&#xff0c;发布图片、视频&#xff0c;分享到联系人群组&#xff0c;直接拍摄等。自带选择图片和选择视频方法。 注意&#xff1a; 使用前&#xff0c;先到抖音开放…

LabVIEW CompactRIO 开发指南 3 选择CompactRIO编程模式

第二章 选择CompactRIO编程模式 第一章中介绍的CompactRIO架构为我们提供了通过LabVIEW FPGA定制FPGA硬件或使用NI CompactRIO扫描模式来实现I/O的选项。如果计算机上有LabVIEW Real-Time和LabVIEW FPGA&#xff0c;那么当向LabVIEW项目添加CompactRIO目标时&#xff0c;将提…

BM48-数据流中的中位数

题目 如何得到一个数据流中的中位数&#xff1f;如果从数据流中读出奇数个数值&#xff0c;那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值&#xff0c;那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流&…

【软考网络管理员】2023年软考网管初级常见知识考点(3)- 网络体系结构

【写在前面】也是趁着五一假期前再写几篇分享类的文章给大家&#xff0c;希望看到我文章能给软考网络管理员备考的您带来一些帮助&#xff0c;5月27号也是全国计算机软件考试统一时间&#xff0c;也就不用去各个地方找资料和代码了。紧接着我就把我整理的一些资料分享给大家哈&…

【Python】selenium工具

目录 1. 安装 2. 测试 3. 无头浏览器 4. 元素定位 5. 页面滑动 6. 按键、填写登录表单 7. 页面切换 Selenium是Web的自动化测试工具&#xff0c;为网站自动化测试而开发&#xff0c;Selenium可以直接运行在浏览器上&#xff0c;它支持所有主流的浏览器&#xff0c;可以接…

【Linux - Shell常用命令】- 判断文件是否存在、去掉文件后缀

目录 一、判断文件是否存在1.1 判断目录是否存在1.2 判断文件是否存在1.3 其他文件类型判断 二、字符串截取&#xff08;去掉文件后缀&#xff09;2.1 获取文件后缀2.2 获取文件前缀 一、判断文件是否存在 1.1 判断目录是否存在 将下面代码保存为dirExist.sh &#xff0c;运行…

隐私权限是什么

导读&#xff1a; 隐私权在现代社会对于人们而言是重要的人格权&#xff0c;而随着互联网技术的发展&#xff0c;实践中侵犯隐私权的行为很常见。那么隐私权限是什么&#xff1f;侵犯隐私权的行为有哪些&#xff1f;侵犯他人隐私权要负什么法律责任&#xff1f;接下来将由找法…

Linux-修改虚拟机为静态IP 和 主机名

一、设置虚拟机的IP为静态的 一般情况下&#xff0c;NAT网络连接模式下&#xff0c;DHCP动态分配IP地址的&#xff0c;但这样在每次访问连接Linux虚拟机时&#xff0c;都要先去查询ip地址&#xff0c;很麻烦&#xff0c;干脆就将虚拟机IP地址写死&#xff0c;也就是设置为静态…

数据结构初阶 —— 树(二叉树)

目录 一&#xff0c;二叉树 特殊二叉树 二叉树的性质 二叉树的存储结构 二&#xff0c;二叉树链式结构 二叉树的遍历&#xff08;四种&#xff09; 二叉树接口 试题 一&#xff0c;二叉树 由一个根节点&#xff0c;加上两颗左二叉树和右二叉树组成&#xff0c;可以为空…

python cms建站教程:Wagtail建站(一、安装与基本使用)

最近有个建站的项目&#xff0c;因为python比较熟&#xff0c;为了快速建站想着用cms&#xff0c;但发现网上关于python cms的教程很少&#xff0c;于是自己试着写一个。建站工具采用Wagtail&#xff0c;是一款基于Django框架的cms&#xff0c;自己照着文档摸索了一番&#xff…

线性调频Z变换 CZT

文章目录 【1. 原理】【2. z k z_k zk​ 所在的路径】【3. CZT的实现步骤】【4. CZT的特点 】【5. CZT的应用】5.1 通过 CZT 变换求 DFT5.2 对信号的频谱进行细化分析5.3 求解Z变换X(z)的零、极点5.4 使用CZT进行Keystone变换 【6.相关文献】 线性调频Z变换&#xff08;chirp …

FL Studio中文版V21的主要功能与下载教程

FL Studio21最新版是流行的数字音频工作站(DAW)其最新版本FL Studio 21,主要功能和下载教程如下: FL Studio21中文版功能介绍: 1. 全新界面:采用简洁现代的设计风格,工具栏和菜单进行重组,更加直观。提供智能提示与工作流指导,易于学习和操作。 2. 多显示器支持:可以在不同屏…

野火STM32电机系列(六)Cubemx配置ADC规则和注入通道

前文已经配置了GPIO、编码器 本节讲解CubeMXADC规则和注入通道 本文adc注入通道采用定时器触发&#xff0c;因此在上文定时器配置的基础上进行 常规信号&#xff08;温度等&#xff09;使用带DMA的常规通道连续采样 注入采样由定时器触发&#xff0c;采集电机三相电流&…

科大版中国版ChatGPT来啦!抢先体验

随着文心一言、通义千问等国内顶尖级ChatGPT大模型相继问世&#xff0c;具有语言理解和生成能力的人工智能正在引领行业创新发展。作为人工智能公司中的佼佼者&#xff0c;科大讯飞也开始加入到这场竞争中来。 4月20日&#xff0c;科大讯飞宣布即将于5月6日正式发布其最新的“…

【QT5:CAN卡通信的上位机-代码练习-收发数据+布局+引用外部库+基础样例(1)】

【QT5:CAN卡通信的上位机-代码练习-收发数据布局引用外部库基础样例1】 1、概述2、实验环境3、自我总结和提升4、事先声明5、效果展示6、代码编写过程&#xff08;1&#xff09;操作步骤部分1、新建工程2、加入外部库&#xff0c;并且加入qt工程中3、ui页面布局4、代码练习5、运…

荔枝派Zero(全志V3S)基于QT实现在LCD显示图片

文章目录 前言一、配置 buildroot 及编译二、写 QT 代码三、编译可执行文件四、拷贝到 SD 卡五、上板子测试六、资源自取 前言 有这样一个需求&#xff0c;通过配置 QT&#xff0c;在 linux 下实现显示我所想要显示的图片&#xff0c;实现的方式是我可以在命令行将图片的路径作…