每个程序员都应该自己写一个的:socket包装类
每个程序员都应该有自己的网络类。
下面是我自己用的socket类,支持所有我自己常用的功能,支持windows和unix/linux。
目录
客户端
服务端
非阻塞
获取socket信息
完整代码
客户端
作为socket客户端,只需要如下几个功能:
//连接到指定的域名/地址和端口
bool Connect(const string & host, unsigned short port);//发送数据
bool Send(const string & str);//发送文本
bool Send(char const * buf, long count);//发送二进制数据//接收数据
bool Recv(char * buf, int buflen, long * pReadCount);//断开连接
bool Close();
比较复杂的是连接到服务器,因为要处理域名和端口,还要处理主机字节序和网络字节序的转换,但是写好以后就可以简单地用域名/地址和端口调用了。判断传入的参数是域名还是地址可以直接尝试转换成地址,如果失败再进行域名解析。
Connect代码如下:
bool Connect(const string & host, unsigned short port)//连接到指定的目标{if (isSTDOUT)return false;struct hostent *ph;T_SA_SIZE len_sa = sizeof(struct sockaddr_in);if (s >= 0){cout << "不能在已打开的socket上操作 " << s << endl;return false;}if (!CreateSocket()){cout << "socket创建失败 " << s << endl;return false;}peersa.sin_family = AF_INET;peersa.sin_port = htons(port);if (-1 == (long)(peersa.sin_addr.s_addr = inet_addr(host.c_str()))){if (NULL == (ph = gethostbyname(host.c_str())))return false;memcpy(&peersa.sin_addr.s_addr, ph->h_addr_list[0], ph->h_length);}if (connect(s, (sockaddr*)(void*)&peersa, sizeof(struct sockaddr_in)) < 0){Close();return false;}getsockname(s, (sockaddr*)(void*)&mysa, &len_sa);getpeername(s, (sockaddr*)(void*)&peersa, &len_sa);int iKeepAlive = 1;setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&iKeepAlive, sizeof(iKeepAlive));return true;}
服务端
作为服务端,关键是这两个功能:
//在指定端口上监听
bool Listen(unsigned short portnum);//接受一个连接请求,返回一个新CmySocket对象
CmySocket Accept();
Listen其实相当简单,只要先bind到端口即可,当然还可能需要指定使用的IP,不过我的程序没有用到,所以没有写:
bool Bind(unsigned short portnum)//绑定到端口
{if (s < 0 && !CreateSocket())return false;int on = 1;setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));mysa.sin_port = htons(portnum);if (bind(s, (sockaddr*)(void*)&mysa, sizeof(struct sockaddr_in)) < 0){Close();return false;}return true;
}bool Listen(unsigned short portnum)
{return (Bind(portnum)) && (!(listen(s, SOMAXCONN) < 0));
}
非阻塞
一般用select查询socket是否可读就可以解决阻塞问题(写操作不会阻塞)。但是,有一个坑:
如果并发执行select,会同时得到可读,从而所有进程或线程进入读操作(通常是服务端的accept操作),但是,只有其中一个能读到,其它进程或线程会被阻塞。这种现象叫做“惊群”。
对select加锁可以解决问题,但是会降低性能。服务端应该通过别的方式来解决(一般要解决的只是让服务端能遵照指令退出而已)。
通过select检查socket是否可读的代码如下:
bool IsSocketReadReady(struct timeval & timeout, bool & ret){fd_set fd;int i;FD_ZERO(&fd);FD_SET(s, &fd);i = select(s + 1, &fd, NULL, NULL, &timeout);if (1 == i){ret = true;return true;}else if (0 == i){ret = false;return true;}else if (-1 == i){ret = false;return false;}return false;}
还有一个能够快速退出的版本:
//检查套接字是否可读,seconds为负不设超时,但仍可根据pfNeedBrek跳出bool IsSocketReadReady2(long seconds, bool & ret, bool(*pfNeedBrek)() = NULL){struct timeval timeout;timeout.tv_sec = (0 == seconds ? 0 : 1);timeout.tv_usec = 0;time_t t1 = time(NULL);do{//LOG<<seconds<<" "<<time(NULL) - t1<<ENDI;if (!IsSocketReadReady2(timeout, ret)){return false;}if (NULL != pfNeedBrek && pfNeedBrek()){if (isDebug)cout << "need break:" << s << endl;return false;}if (ret){return true;}} while (seconds < 0 || time(NULL) - t1 < seconds);return true;}
每次阻塞一秒钟,然后检查是否设置了退出命令。当然我们知道UNIX/Linux的标准的机制是使用信号来中断,不过信号机制可能不同模块冲突,不如靠自己。
获取socket信息
程序调试经常要知道本地的端口和对方的地址端口,这是通过调用getsockname和getpeername来实现的:
//成员变量public:bool isDebug;//调试输出private:bool isSTDOUT;//输出到标准输出而不是socketint s;//socket -1表示无效unsigned long sendcount;//发送计数unsigned long recvcount;//接收计数struct sockaddr_in mysa;//本地半相关struct sockaddr_in peersa;//远程半相关//服务端接受连接或客户端建立连接后执行:
getsockname(cs.s, (sockaddr*)(void*)&cs.mysa, &len_sa);
getpeername(cs.s, (sockaddr*)(void*)&cs.peersa, &len_sa);//输出内部信息string debuginfo()//输出内部数据结构{string str;char buf[256];str = "";if (isSTDOUT)str += "STDOUT\n";if (-1 != s){sprintf(buf, "%d", s);str += buf;}else str += "未连接";str += "\n";sprintf(buf, "send: %ld\nrecv: %ld\n", sendcount, recvcount);str += buf;if (AF_INET == mysa.sin_family)str += "AF_INET";else{sprintf(buf, "%d", mysa.sin_family);str += buf;}str += "\n";str += inet_ntoa(mysa.sin_addr);str += "\n";sprintf(buf, "%d", ntohs(mysa.sin_port));str += buf;str += "\n";if (AF_INET == peersa.sin_family)str += "AF_INET";else{sprintf(buf, "%d", peersa.sin_family);str += buf;}str += "\n";str += inet_ntoa(peersa.sin_addr);str += "\n";sprintf(buf, "%d", ntohs(peersa.sin_port));str += buf;str += "\n";return str;}
完整代码
#ifndef MYSTD_MYSOCKET_H
#define MYSTD_MYSOCKET_H#ifndef _MS_VC
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
#else
#include "winsock.h"
#endifnamespace ns_my_std_2
{#define T_SA_SIZE int#ifdef _HPOS
#undef T_SA_SIZE
#define T_SA_SIZE int
#endif#ifdef _IBMOS
#undef T_SA_SIZE
#define T_SA_SIZE unsigned int
#endif#ifdef _LINUXOS
#undef T_SA_SIZE
#define T_SA_SIZE socklen_t
#endifclass CmySocket{public:bool isDebug;//调试输出private:bool isSTDOUT;//输出到标准输出而不是socketint s;//socket -1表示无效unsigned long sendcount;//发送计数unsigned long recvcount;//接收计数struct sockaddr_in mysa;//本地半相关struct sockaddr_in peersa;//远程半相关bool Init()//初始化,s被设置为-1,计数清零,半相关清零{char myname[256];struct hostent *ph;s = -1;isDebug = false;isSTDOUT = false;sendcount = 0;recvcount = 0;memset(&mysa, 0, sizeof(struct sockaddr_in));memset(&peersa, 0, sizeof(struct sockaddr_in));if (0 != gethostname(myname, 256))return false;myname[255] = '\0';if (NULL == (ph = gethostbyname(myname)))return false;mysa.sin_family = ph->h_addrtype;return true;}bool CreateSocket()//初始化并建立一个socket{if (Init() && (s = socket(AF_INET, SOCK_STREAM, 0)) > 0)return true;else return false;}int CloseSocket(int _s){
#ifndef _MS_VCreturn close(_s);
#elsereturn closesocket(_s);
#endif}bool Bind(unsigned short portnum)//绑定到端口{if (s < 0 && !CreateSocket())return false;int on = 1;setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));mysa.sin_port = htons(portnum);if (bind(s, (sockaddr*)(void*)&mysa, sizeof(struct sockaddr_in)) < 0){Close();return false;}return true;}public:CmySocket(int _s = -1)//构造函数,s默认被设置为-1{T_SA_SIZE len_sa = sizeof(struct sockaddr_in);Init();s = _s;if (-1 != s){getsockname(s, (sockaddr*)(void*)&mysa, &len_sa);getpeername(s, (sockaddr*)(void*)&peersa, &len_sa);}}void SetSTDOUT() { isSTDOUT = true; }//设置为标准输出bool Listen(unsigned short portnum)//在指定端口上监听,如果s为-1会先建立socket然后bind{if (isSTDOUT)return false;return (Bind(portnum)) && (!(listen(s, SOMAXCONN) < 0));}bool Accept(int * pNewSocket)//接受一个连接请求{if (isSTDOUT)return false;return -1 != ((*pNewSocket) = accept(s, NULL, NULL));}CmySocket Accept()//接受一个连接请求,返回一个新CmySocket对象{if (isSTDOUT)return false;CmySocket cs;T_SA_SIZE len_sa = sizeof(struct sockaddr_in);cs.Init();cs.s = accept(s, (sockaddr*)(void*)&cs.mysa, &len_sa);if (-1 != cs.s){getsockname(cs.s, (sockaddr*)(void*)&cs.mysa, &len_sa);getpeername(cs.s, (sockaddr*)(void*)&cs.peersa, &len_sa);int iKeepAlive = 1;setsockopt(cs.s, SOL_SOCKET, SO_KEEPALIVE, (void *)&iKeepAlive, sizeof(iKeepAlive));}return cs;}bool Send(const string & str)//发送文本{return Send(str.c_str(), str.size());}bool Send(char const * buf, long count)//发送二进制数据{if (isSTDOUT){std::cout << buf << std::flush;sendcount += count;return true;}long i = 0;while (i < count){int n = send(s, buf + i, count - i, 0);if (isDebug)cout << "socket " << s << " send " << count - i << " return " << n << endl;if (n != count){cout << "socket " << s << " send " << count - i << " return " << n << endl;}if (n < 0){return false;}i += n;sendcount += n;}return true;}bool Recv(char * buf, int buflen, long * pReadCount)//接收数据{if (isSTDOUT)return false;if ((*pReadCount = recv(s, buf, buflen, 0)) < 0){if (isDebug)cout << "socket " << s << " recv return " << *pReadCount << endl;return false;}if (isDebug)cout << "socket " << s << " recv return " << *pReadCount << endl;recvcount += (*pReadCount);return true;}bool Close()//close socket 设置s为-1,但其它数据会保持到下一次用这个对象建立新socket时才清除{if (isSTDOUT)return true;if (isDebug)cout << "socket 关闭:" << s << endl;shutdown(s, 2);if (0 == CloseSocket(s)){s = -1;return true;}else return false;}bool Connect(const string & host, unsigned short port)//连接到指定的目标{if (isSTDOUT)return false;struct hostent *ph;T_SA_SIZE len_sa = sizeof(struct sockaddr_in);if (s >= 0){cout << "不能在已打开的socket上操作 " << s << endl;return false;}if (!CreateSocket()){cout << "socket创建失败 " << s << endl;return false;}peersa.sin_family = AF_INET;peersa.sin_port = htons(port);if (-1 == (long)(peersa.sin_addr.s_addr = inet_addr(host.c_str()))){if (NULL == (ph = gethostbyname(host.c_str())))return false;memcpy(&peersa.sin_addr.s_addr, ph->h_addr_list[0], ph->h_length);}if (connect(s, (sockaddr*)(void*)&peersa, sizeof(struct sockaddr_in)) < 0){Close();return false;}getsockname(s, (sockaddr*)(void*)&mysa, &len_sa);getpeername(s, (sockaddr*)(void*)&peersa, &len_sa);int iKeepAlive = 1;setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&iKeepAlive, sizeof(iKeepAlive));return true;}bool IsConnected() { if (isSTDOUT)return true; else return -1 != s; }//是否处于连接状态,只对客户socket有意义sockaddr_in const * GetPeersa()const { return &this->peersa; }//检查套接字是否可读bool IsSocketReadReady(long seconds, bool & ret){struct timeval timeout;timeout.tv_sec = seconds;timeout.tv_usec = 0;return IsSocketReadReady(timeout, ret);}bool IsSocketReadReady(struct timeval & timeout, bool & ret){fd_set fd;int i;FD_ZERO(&fd);FD_SET(s, &fd);i = select(s + 1, &fd, NULL, NULL, &timeout);if (1 == i){ret = true;return true;}else if (0 == i){ret = false;return true;}else if (-1 == i){ret = false;return false;}return false;}//检查套接字是否可读,seconds为负不设超时,但仍可根据pfNeedBrek跳出bool IsSocketReadReady2(long seconds, bool & ret, bool(*pfNeedBrek)() = NULL){struct timeval timeout;timeout.tv_sec = (0 == seconds ? 0 : 1);timeout.tv_usec = 0;time_t t1 = time(NULL);do{//LOG<<seconds<<" "<<time(NULL) - t1<<ENDI;if (!IsSocketReadReady2(timeout, ret)){return false;}if (NULL != pfNeedBrek && pfNeedBrek()){if (isDebug)cout << "need break:" << s << endl;return false;}if (ret){return true;}} while (seconds < 0 || time(NULL) - t1 < seconds);return true;}bool IsSocketReadReady2(struct timeval & timeout, bool & ret){ret = false;fd_set fd;int i;FD_ZERO(&fd);FD_SET(s, &fd);//LOG<<"timeout.tv_sec "<<timeout.tv_sec<<ENDI;
#ifdef _HPOSi = select(s + 1, (int *)&fd, NULL, NULL, &timeout);
#elsei = select(s + 1, &fd, NULL, NULL, &timeout);
#endif//LOG<<"timeout.tv_sec "<<timeout.tv_sec<<" select "<<i<<ENDI;if (1 == i){ret = true;return true;}else if (0 == i){ret = false;return true;}else if (-1 == i){if (EINTR == errno){ret = false;return true;//被信号中断不是错误}else{ret = false;return false;}}return false;}//接收数据,可以设置函数来终止bool Recv2(char * buf, int buflen, long * pReadCount, bool(*pfNeedBrek)()){bool isReady = false;if (!IsSocketReadReady2(-1, isReady, pfNeedBrek)){if (isDebug)cout << "IsSocketReadReady2 error:" << s << endl;return false;}if (!isReady){if (isDebug)cout << "not ready:" << s << endl;return false;}return Recv(buf, buflen, pReadCount);}int GetMyPort()const{return ntohs(mysa.sin_port);}string GetPeerInfo()const{string str;if (-1 != s){str += inet_ntoa(peersa.sin_addr);str += ":";char buf[32];sprintf(buf, "%d", ntohs(peersa.sin_port));str += buf;}return str;}string debuginfo()//输出内部数据结构{string str;char buf[256];str = "";if (isSTDOUT)str += "STDOUT\n";if (-1 != s){sprintf(buf, "%d", s);str += buf;}else str += "未连接";str += "\n";sprintf(buf, "send: %ld\nrecv: %ld\n", sendcount, recvcount);str += buf;if (AF_INET == mysa.sin_family)str += "AF_INET";else{sprintf(buf, "%d", mysa.sin_family);str += buf;}str += "\n";str += inet_ntoa(mysa.sin_addr);str += "\n";sprintf(buf, "%d", ntohs(mysa.sin_port));str += buf;str += "\n";if (AF_INET == peersa.sin_family)str += "AF_INET";else{sprintf(buf, "%d", peersa.sin_family);str += buf;}str += "\n";str += inet_ntoa(peersa.sin_addr);str += "\n";sprintf(buf, "%d", ntohs(peersa.sin_port));str += buf;str += "\n";return str;}};
}#endif
(这里是结束)
相关文章:
每个程序员都应该自己写一个的:socket包装类
每个程序员都应该有自己的网络类。 下面是我自己用的socket类,支持所有我自己常用的功能,支持windows和unix/linux。 目录 客户端 服务端 非阻塞 获取socket信息 完整代码 客户端 作为socket客户端,只需要如下几个功能: //…...
JMeter:断言之响应断言
一、断言的定义 断言用于验证取样器请求或对应的响应数据是否返回了期望的结果。可以是看成验证测试是否预期的方法。 对于接口测试来说,就是测试Request/Response,断言即可以针对Request进行,也可以针对Response进行。但大部分是对Respons…...
RLHF的替代算法之DPO原理解析:从Zephyr的DPO到Claude的RAILF
前言 本文的成就是一个点顺着一个点而来的,成文过程颇有意思 首先,如上文所说,我司正在做三大LLM项目,其中一个是论文审稿GPT第二版,在模型选型的时候,关注到了Mistral 7B(其背后的公司Mistral AI号称欧洲…...
U盘显示无媒体怎么办?方法很简单
当出现U盘无媒体情况时,您可以在磁盘管理工具中看到一个空白的磁盘框,并且在文件资源管理器中不会显示出来。那么,导致这种问题的原因是什么呢?我们又该怎么解决呢? 导致U盘无媒体的原因是什么? 当您遇到上…...
进销存管理系统如何提高供应链效率?
供应链和进销存系统之间有着密切的联系。进销存系统是供应链管理的一部分,用于跟踪和管理产品的采购、库存和销售。进销存管理是供应链管理的核心流程之一,它有助于提高效率、降低成本、增加盈利,同时确保客户满意度,这对于企业的…...
用AI魔法打败AI魔法
全文均为AI创作。 此为内容创作模板,在发布之前请将不必要的内容删除当前,AI技术的广泛应用为社会公众提供了个性化智能化的信息服务,也给网络诈骗带来可乘之机,如不法分子通过面部替换语音合成等方式制作虚假图像、音频、视频仿…...
Java 中的final:不可变性的魔法之旅
🎏:你只管努力,剩下的交给时间 🏠 :小破站 Java 中的final:不可变性的魔法之旅 前言第一:了解final变量第二:final方法第三:final类第四:final参数第五&#…...
Alfred 5 for mac(最好用的苹果mac效率软件)中文最新版
Alfred 5 Mac是一款非常实用的工具,它可以帮助用户更加高效地使用Mac电脑。用户可以学会使用快捷键、全局搜索、快速启动应用程序、使用系统维护工具、快速复制粘贴文本以及自定义设置等功能,以提高工作效率。 Alfred for Mac 的一些主要功能包括&#…...
常见的Python解释器,你了解多少?
Python,作为一种解释型编程语言,它的运行过程也遵循“程序源码—>解释器(字节码)—>虚拟机(可执行文件)”的流程。 在编写Python程序时,是在扩展名为.py的文件中进行编写,.py…...
在 Python 中使用 Selenium 按文本查找元素
我们将通过示例介绍在Python中使用selenium通过文本查找元素的方法。 在 Python 中使用 Selenium 按文本查找元素 软件测试是检查应用程序是否满足用户需求的技术。 该技术有助于使应用程序成为无错误的应用程序。 软件测试可以手动完成,也可以通过某些软件完成。…...
【Notepad++】搜索返回窗口(find result)被隐藏或遮挡如何恢复?
Notepad 搜索返回窗口被隐藏或遮挡如何恢复 1:F72:F12恢复之后可以多看一些Notepad中快捷键的使用,以备不时之需。 1:F7 打开任意文件,搜索任意内容,按F7,焦点切换到Find result。 按AltSpace,出现小窗口点击"移动…...
应用软件安全编程--05预防 XML 注入
如果用户有能力使用结构化XML 文档作为输入,那么他能够通过在数据字段中插入 XML 标签来 重写这个 XML 文档的内容。 XML 解析器会将这些标签按照正常标签进行解析。下面是一段在线商 店的 XML 代码,主要用于查询后台数据库。 <item)<descri…...
JavaEE-博客系统3(功能设计)
本部分内容为:实现登录功能;强制要求用户登录;实现显示用户信息;退出登录;发布博客 该部分的后端代码如下: Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws Ser…...
椭圆滤波器
之前的文章 信号去噪 中列出了7种常用的信号去噪算法,对于后两种算法——深度学习和奇异值分解(SVD),我现在也不太理解,就先不写了。 很多朋友留言又提了一些算法,今天一起来聊聊椭圆滤波器。 椭圆滤波器(Elliptic F…...
Mac 下安装golang环境
一、下载安装包 安装包下载地址 下载完成,直接继续----->下一步到结束即可安装成功; 安装成功之后,验证一下; go version二、配置环境变量 终端输入vim ~/.zshrc进入配置文件,输入i进行编辑 打开的不管是空文本…...
前端面试大纲
一、CSS 1.说一下CSS的盒模型。 在HTML页面中的所有元素都可以看成是一个盒子 盒子的组成:内容content、内边距padding、边框border、外边距margin 盒模型的类型: 标准盒模型 margin border padding content IE盒模型 margin content(border padd…...
CAN(Controller Area Network)是一种用于在汽车和工业领域中进行通信的串行总线系统(附加案例)
CAN(Controller Area Network)是一种用于在汽车和工业领域中进行通信的串行总线系统。它是一种高可靠性、多主机、多节点通信协议,主要用于实时控制和数据传输。 CAN数据是指在CAN总线上通过CAN协议进行通信传输的数据。CAN总线上的数据被分…...
代码随想录day53|1143.最长公共子序列、 1035.不相交的线、 53. 最大子序和
1143.最长公共子序列 dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j] 因此是if(nums1[i-1] nums2[j-1]) 1035.不相交的线 和上一题一样 53. 最大子序和 int result dp[0]; 不是0,因为dp[i]有…...
xilinx fpga ddr mig axi
硬件 参考: https://zhuanlan.zhihu.com/p/97491454 https://blog.csdn.net/qq_22222449/article/details/106492469 https://zhuanlan.zhihu.com/p/26327347 https://zhuanlan.zhihu.com/p/582524766 包括野火、正点原子的资料 一片内存是 1Gbit 128MByte 16bit …...
《golang设计模式》第三部分·行为型模式-04-迭代器模式(Iterator)
文章目录 1. 概念1.1 角色1.2 类图 2. 代码示例2.1 需求2.2 代码2.3 类图 1. 概念 迭代器(Iterator)能够在不暴露聚合体内部表示的情况下,向客户端提供遍历聚合元素的方法。 1.1 角色 InterfaceAggregate(抽象聚合)…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...
在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例
目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码:冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...
云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
怎么开发一个网络协议模块(C语言框架)之(六) ——通用对象池总结(核心)
+---------------------------+ | operEntryTbl[] | ← 操作对象池 (对象数组) +---------------------------+ | 0 | 1 | 2 | ... | N-1 | +---------------------------+↓ 初始化时全部加入 +------------------------+ +-------------------------+ | …...
