当前位置: 首页 > news >正文

Windows C++ TCP开发(使用select函数以及设置非阻塞/Reuse属性)

1、select官方函数说明:

语法

C++

int WSAAPI select([in]      int           nfds,[in, out] fd_set        *readfds,[in, out] fd_set        *writefds,[in, out] fd_set        *exceptfds,[in]      const timeval *timeout
);

参数

[in] nfds

已忽略。 包含 nfds 参数只是为了与 Berkeley 套接字兼容。

[in, out] readfds

一个可选指针,指向要检查的一组套接字的可读性。

[in, out] writefds

指向要检查可写性的一组套接字的可选指针。

[in, out] exceptfds

指向要检查错误的一组套接字的可选指针。

[in] timeout

选择等待的最长时间,以 TIMEVAL 结构的形式提供。 将阻止操作的 超时 参数设置为 null 。

返回值

select 函数返回fd_set结构中已就绪并包含的套接字句柄总数;如果时间限制过期,则返回 0;如果发生错误,则返回SOCKET_ERROR。 如果返回值SOCKET_ERROR,则 WSAGetLastError 可用于检索特定的错误代码。

 2、阻塞设置

    unsigned   long cmd = 1;
    nRet = ioctlsocket(sclient, FIONBIO, &cmd);
    if (SOCKET_ERROR == nRet)
    {
        printf("Failed to set FIONBIOsocket!\n");
        WSACleanup();
        return 0;
    }

3、设置端口 Reuse属性

    bool bReuseAddr = true;
    //设置端口SO_REUSEADDR属性,端口释放后可以立即被使用。
    nRet = setsockopt(sclient, SOL_SOCKET, SO_REUSEADDR, (char *)&bReuseAddr, sizeof(bReuseAddr));
    if (SOCKET_ERROR == nRet)
    {
        printf("Failed to set resueaddr socket!\n");
        WSACleanup();
        return 0;
    }

 什么是resuse属性:端口复用最常用的用途应该是防止服务器重启时之前绑定的端口还未释放或者程序突然退出而系统没有释放端口。这种情况下如果设定了端口复用,则新启动的服务器进程可以直接绑定端口。如果没有设定端口复用,绑定会失败,提示ADDR已经在使用中,必须等超时时间大概是2分钟。

4、TCP代码+select
4.1 TCP 服务端代码

#include <iostream>
#include <stdio.h>  
#include <string.h>  
#include <WINSOCK2.H>  

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

#define INT_SERVER_PORT 8888  
#define STR_SERVER_IP "127.0.0.1"  
#define INT_DATABUFFER_SIZE 100  

void main(void)
{
    //与WSACleanup函数配对使用
    WORD dwVersion = MAKEWORD(2, 2);
    WSAData wsaData;
    WSAStartup(WINSOCK_VERSION, &wsaData);

    //创建套接字
    SOCKET sockServer = socket(AF_INET, SOCK_STREAM, 0);
    if (INVALID_SOCKET == sockServer)
    {
        printf("Failed to create socket!\n");
        WSACleanup();
        return;
    }

    //本地地址初始化
    sockaddr_in addrServer;
    memset(&addrServer, 0, sizeof(sockaddr_in));
    addrServer.sin_family = AF_INET;
    addrServer.sin_port = htons(INT_SERVER_PORT);
    addrServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

    int nRet = 0;
    bool bReuseAddr = true;
    //设置端口SO_REUSEADDR属性,端口释放后可以立即被使用。
    nRet = setsockopt(sockServer, SOL_SOCKET, SO_REUSEADDR, (char *)&bReuseAddr, sizeof(bReuseAddr));
    if (SOCKET_ERROR == nRet)
    {
        printf("Failed to set resueaddr socket!\n");
        WSACleanup();
        return;
    }

    //设置端口非阻塞
    unsigned   long cmd = 1;
    nRet = ioctlsocket(sockServer,FIONBIO,&cmd);
    if (SOCKET_ERROR == nRet)
    {
        printf("Failed to set resueaddr socket!\n");
        WSACleanup();
        return;
    }

    nRet = bind(sockServer, (sockaddr *)&addrServer, sizeof(addrServer));
    if (SOCKET_ERROR == nRet)
    {
        printf("Failed to bind address!\n");
        WSACleanup();
        return;
    }

    if (0 != listen(sockServer, 5))
    {
        printf("Failed to listen client!\n");
        WSACleanup();
        return;
    }

    UINT i = 0;
    fd_set fd;
    FD_ZERO(&fd);
    FD_SET(sockServer, &fd);

    /*
    timeval tm;
    tm.tv_sec = 0;
    tm.tv_usec = 1000;
    */
    while (1)
    {
        fd_set fdOld = fd;
        nRet = select(0, &fdOld, NULL, NULL,/*&tm*/NULL);
        if (0 <= nRet)
        {
            for (i = 0; i < fd.fd_count; i++)
            {
                if (FD_ISSET(fd.fd_array[i], &fdOld))
                {
                    if (fd.fd_array[i] == sockServer)//接收到新的连接
                    {
                        SOCKET sockAccept;
                        sockaddr_in addrAccept;
                        int iAcceptLen = sizeof(addrAccept);
                        memset(&addrAccept, 0, sizeof(addrAccept));
                        sockAccept = accept(sockServer, (sockaddr *)&addrAccept, &iAcceptLen);
                        if (INVALID_SOCKET != sockAccept)
                        {
                            send(sockAccept, "Hello Client", strlen("Hello Client"), 0);
                            FD_SET(sockAccept, &fd);
                            printf("%s:%d has connected server!\n", inet_ntoa(addrAccept.sin_addr),
                                ntohs(addrAccept.sin_port));
                        }
                    }
                    else //非服务器,接收数据(因为fd是读数据集)  
                    {
                        char szDataBuff[INT_DATABUFFER_SIZE];
                        int iRecvSize;
                        memset(szDataBuff, 0, INT_DATABUFFER_SIZE);
                        iRecvSize = recv(fd.fd_array[i], szDataBuff, INT_DATABUFFER_SIZE, 0);
                        if (SOCKET_ERROR == iRecvSize)
                        {
                            closesocket(fd.fd_array[i]);
                            FD_CLR(fd.fd_array[i], &fd);
                            i--;
                            printf("Failed to recv data ,or Client has disconnected, errorcode:%d.\n", WSAGetLastError());
                            continue;
                        }

                        if (0 == iRecvSize)
                        {
                            //客户socket关闭  
                            closesocket(fd.fd_array[i]);
                            FD_CLR(fd.fd_array[i], &fd);
                            i--;
                        }

                        if (0 < iRecvSize)
                        {
                            //打印接收的数据  
                            printf("recv data:%s\n",szDataBuff);
                        }
                    }
                }
            }
        }
        else if (SOCKET_ERROR == nRet)
        {
            printf("Faild to select sockt in server! Error Code[%d]\n", WSAGetLastError());
            Sleep(100);
        }
    }
    WSACleanup();
}
 

4.2 TCP客户端代码 

#include <iostream>
#include <stdio.h>  
#include <string.h>  
#include <WINSOCK2.H>  
using namespace std;
#pragma comment(lib, "ws2_32.lib")

int main()
{
    //与WSACleanup函数配对使用
    WORD sockVersion = MAKEWORD(2, 2);
    WSADATA data;
    if (WSAStartup(sockVersion, &data) != 0)
    {
        return 0;
    }

    //创建客户端套接字
    SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sclient == INVALID_SOCKET)
    {
        printf("invalid socket!");
        return 0;
    }

    //初始化SOCKET结构体
    sockaddr_in serAddr;
    serAddr.sin_family = AF_INET;
    serAddr.sin_port = htons(8888);
    serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
    {  //连接失败 
        printf("connect error !");
        closesocket(sclient);
        return 0;
    }

    int nRet = 0;
    bool bReuseAddr = true;
    //设置端口SO_REUSEADDR属性,端口释放后可以立即被使用。
    nRet = setsockopt(sclient, SOL_SOCKET, SO_REUSEADDR, (char *)&bReuseAddr, sizeof(bReuseAddr));
    if (SOCKET_ERROR == nRet)
    {
        printf("Failed to set resueaddr socket!\n");
        WSACleanup();
        return 0;
    }

    //设置端口非阻塞
    unsigned   long cmd = 1;
    nRet = ioctlsocket(sclient, FIONBIO, &cmd);
    if (SOCKET_ERROR == nRet)
    {
        printf("Failed to set resueaddr socket!\n");
        WSACleanup();
        return 0;
    }

    //发送数据
    send(sclient, "Hello Server", strlen("Hello Server"), 0);

    //接收数据
    while (true)
    {
        fd_set fd;
        FD_ZERO(&fd);
        FD_SET(sclient, &fd);
        nRet = select(0, &fd, NULL, NULL,NULL);
        if (0 <= nRet)
        {
            char recData[255];
            int ret = recv(sclient, recData, 255, 0);
            if (ret > 0) {
                recData[ret] = 0x00;
                printf("Recv :%s\n",recData);
            }
            else
            {
                printf("Socket Error or Socket has closed\n");
                break;
            }
        }
        else if (nRet == SOCKET_ERROR)
        {
            printf("Faild to select sockt in server! Error Code[%d]\n", WSAGetLastError());
            break;
        }
    }
    closesocket(sclient);
    WSACleanup();
    return 0;
}

相关文章:

Windows C++ TCP开发(使用select函数以及设置非阻塞/Reuse属性)

1、select官方函数说明&#xff1a; 语法 C int WSAAPI select([in] int nfds,[in, out] fd_set *readfds,[in, out] fd_set *writefds,[in, out] fd_set *exceptfds,[in] const timeval *timeout );参数 [in] nfds 已忽略。 包含 nf…...

ARM TrustZone技术解析:构建嵌入式系统的安全扩展基石

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-LOdvohfCEnd8eKyd {font-family:"trebuchet ms",verdana,arial,sans-serif;f…...

初识Python语言-课堂练习【pyhton123题库】

初识Python语言-课堂练习【pyhton123题库】 一、单项选择题 1、Guido van Rossum正式对外发布Python版本的年份是&#xff1a; A 2008B 1998C 1991D 2002 【答案】C 【解析】暂无解析2、下面不是Python语言特点的是&#xff1a;‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪…...

chrome高内存占用问题

chrome号称内存杀手不是盖的&#xff0c;不设设置的话&#xff0c;经常被它内存耗尽死机是常事。以下自用方法 1 自带的memory saver chrome://settings/performance PerformanceMemory Saver When on, Chromium frees up memory from inactive tabs. This gives active tab…...

【C语言】文件操作篇-----程序文件和数据文件,文件的打开和关闭,二进制文件和文本文件,fopen,fclose【图文详解】

欢迎来CILMY23的博客喔&#xff0c;本篇为【C语言】文件操作篇-----程序文件和数据文件&#xff0c;文件的打开和关闭&#xff0c;二进制文件和文本文件【图文详解】&#xff0c;感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞关注收藏。 前言 在了解完动态内存管…...

知识碎片收集

目录 1. 如何计算两点经纬度之间的距离2. 加权随机采样3.什么时LLDB和GDB 1. 如何计算两点经纬度之间的距离 1.知乎-如何计算两点经纬度间距离 2.根据两点经纬度坐标计算距离 3.根据经纬度计算两点之间的距离的公式推导过程以及google.maps的测距函数 4.根据经纬度点计算经…...

不可不知!用例图的绘制与应用全指南深度解析

在软件开发领域中&#xff0c;用例图是一种强大的工具&#xff0c;用于描述系统的功能需求以及系统与外部实体之间的交互。无论是在需求分析阶段还是在系统设计过程中&#xff0c;用例图都扮演着至关重要的角色。本文将全面介绍用例图的绘制方法和其在软件开发中的应用&#xf…...

【数据结构七】堆与PriorityQueue详解

堆 在Java中有一种数据结构基于队列&#xff0c;并保证操作的数据带有优先级&#xff0c;该数据结构应该提供了两个最基本的操作&#xff0c;一个是返回最高优先级对象&#xff0c;一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)。它的底层使用了堆这种数据结…...

uniapp写支付的操作

支付的时候一般需要几个参数&#xff1a; ‘timeStamp’: 时间戳,‘nonceStr’: 随机字符串&#xff0c;不超过32位‘package’: 下单后接口返回的prepauid‘signType’: 签名的算法‘paySign’: 后端会给前端一个签名sign: data.sign // 根据签名算法生成签名 <template&…...

微信小程序开发系列(二十四)·wxml语法·列表渲染·wx:for-item 和 wx:for-index

目录 1. 如果需要对默认的变量名和下标进行修改&#xff0c;可以使用wx:for-item 和 wx:for-index 2. 将 wx:for 用在 标签上&#xff0c;以渲染一个包含多个节点的结构块 方法一 方法二 3. 总结 3.1 wx:for-item 和 wx:for-index总结 3.2 总结 1. 如果需要对默…...

下载无水印抖音视频

在抖音看到某些视频想下载&#xff0c;却出现无法保存在本地【显示"作品暂时无法保存,链接已复制"】。或者下载的视频有水印。 而某些微信小程序下载可能需要付费或者有水印。其实我们可以直接使用电脑浏览器直接下载。 举个例子: 这是来自王道官方账号的一条视频链…...

L1-039 古风排版(C++)

中国的古人写文字&#xff0c;是从右向左竖向排版的。本题就请你编写程序&#xff0c;把一段文字按古风排版。 输入格式&#xff1a; 输入在第一行给出一个正整数N&#xff08;<100&#xff09;&#xff0c;是每一列的字符数。第二行给出一个长度不超过1000的非空字符串&a…...

springboot项目docker分层构建

一、需求场景 在使用dockerfile构建springboot项目时&#xff0c;速度较慢&#xff0c;用时比较长&#xff0c;为了加快构建docker镜像的速度&#xff0c;采用分层构建的方式 二、构建配置 1、pom.xml配置 <properties><project.build.sourceEncoding>UTF-8<…...

深入理解SPA、CSR与SSR的区别及应用

随着Web技术的快速发展&#xff0c;前端开发架构也在不断演进。在现代Web应用中&#xff0c;单页面应用&#xff08;SPA&#xff09;、客户端渲染&#xff08;CSR&#xff09;和服务器端渲染&#xff08;SSR&#xff09;是三种常见的实现方式&#xff0c;它们各自拥有独特的特性…...

基于电鳗觅食优化算法(Electric eel foraging optimization,EEFO)的无人机三维路径规划(提供MATLAB代码)

一、无人机路径规划模型介绍 无人机三维路径规划是指在三维空间中为无人机规划一条合理的飞行路径&#xff0c;使其能够安全、高效地完成任务。路径规划是无人机自主飞行的关键技术之一&#xff0c;它可以通过算法和模型来确定无人机的航迹&#xff0c;以避开障碍物、优化飞行…...

将SQL数据库转换为Mysql数据库

一、准备工作 1、SQL server安装包与已经有数据的mdf、ldf数据库文件&#xff1b; 2、.net Framework安装包&#xff1b;&#xff08;用于支持SQL Server安装的组件&#xff09; 3、MySql安装包&#xff1b;&#xff08;用于目标数据库的环境安装&#xff09; 4、navicat安装包…...

Java集合进阶

双列集合 单列集合的特点&#xff1a;一次添加一个。 双列集合的特点&#xff1a;一次添加一对/键值对/键值对对象/Entry。 左键&#xff08;不可重复&#xff09;右值&#xff08;可重复&#xff09;&#xff0c;一一对应。 Map是双列集合的顶层接口&#xff0c;他的功能是…...

一.算法基础

目录 1.算法基础 2.算法概念 3.时间复杂度--用来评估算法运行效率的一个式子 如何简单快速的判断算法复杂度? 4.空间复杂度 1.算法基础 2.算法概念 --静态动态 3.时间复杂度--用来评估算法运行效率的一个式子 ----一个单位!!! 1-在什么配置下运行(机器) 2-问题的规模…...

python自学7

第二章第一节面向对象 程序的格式都不一样&#xff0c;每个人填写的方式也有自己的习惯&#xff0c;比如收集个人信息&#xff0c;可能有人用字典字符串或者列表&#xff0c; 类的成员方法 类和对象 构造方法 挨个传输值太麻烦了&#xff0c;也没有方便点的&#xff0c;有&…...

Umi - 刷新后页面报404

Umi 项目本地运行刷新没问题&#xff0c;但是部署之后刷新页面报404。因为Umi 默认是用 browser 模式&#xff0c;需要做一下处理。 以下是官方给出解决方案。 一、解决方案 1. 方案一&#xff1a;改用hashHistory .umirc.js {history: { type: hash }, }这个方案项目打包…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础

第三周 Day 3 &#x1f3af; 今日目标 理解类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;的关系学会定义类的属性、方法和构造函数&#xff08;init&#xff09;掌握对象的创建与使用初识封装、继承和多态的基本概念&#xff08;预告&#xff09; &a…...