高性能 Windows Socket 组件 HP-Socket v3.0.2 正式发布

DuMiYue 2013-11-26 01:15:09
加精

  HP-Socket 是一套通用的高性能 Windows Socket 组件包,包含服务端组件(IOCP 模型)和客户端组件(Event Select 模型),广泛适用于 Windows 平台的 TCP 通信系统。HP-Socket 对通信层实现完全封装,上层应用不必关注通信层的任何细节;HP-Socket 提供基于事件通知模型的 API 接口,能非常简单高效地整合到各类应用程序中;另外,为了让大家能更方便的学习 HP-Socket,特此精心制作了一个功能测试示例(Test Echo)一个性能测试示例(Test Echo-PFM)和一个 PULL 模型测试示例(Test Echo-Pull),用户可以通过这两个测试示例入手,迅速掌握组件的设计思想和使用方法。

* HP-Socket 官方网站:http://www.jessma.org
* HP-Socket 下载地址:http://www.oschina.net/p/hp-socket
------------------------------------------------------------------------------------------------
通用性
  通信组件的唯一职责就是接受和发送字节流,绝对不能参与上层协议解析等工作;
与上层使用者解耦、互不依赖,组件与使用者通过操作接口和监听器接口进行交互,组件实现操作接口为上层提供操作方法;使用者实现监听器接口把自己注册为组件的 Listener,接收组件通知。因此,任何使用者只要实现了监听器接口都可以使用组件;另一方面,甚至可以自己重新写一个实现方式完全不同的组件实现给使用者调用,只要该组件遵从组件的操作接口,这也是 DIP 设计原则的体现。

可用性
  可用性对所有通用组件都是至关重要的,如果太难用还不如自己重头写一个来得方便。因此,组件的操作接口和监听器接口设计得尽量简单易用(通俗来说就是“傻瓜化”),这两个接口的主要方法均不超过 5 个。另外,组件完全封装了所有的底层 Socket 通信,上层应用看不到任何通信细节,不必也不能干预任何通信操作,Socket 连接被抽象为 Connection ID,该参数作为连接标识提供给上层应用识别不同的连接。

高性能
  作为底层的通用组件,性能问题是必须考虑的,绝对不能成为系统的瓶颈。而另一方面,从实际出发,根据客户端组件与服务端组件的性能要求采用不同的 Socket 模型。组件在设计上充分考虑了性能、现实使用情景、可用性和实现复杂性等因素,确保满足性能要求的同时又不会写得太复杂。做出以下两点设计决策:
  客户端:在单独线程中实现 Socket 通信交互。这样可以避免与主线程或其他线程相互干扰;I/O 模型选择 Event Select 通信模型。
  服务端:采用 Windows 平台效率最高的 IOCP 通信模型;利用缓存池技术,在通信的过程中,通常需要频繁的申请和释放内存缓冲区,建立了动态缓存池, 只有当缓存池中没有可用对象时才创建新对象,而当缓存对象过多时则会压缩缓存池;另外,组件的动态内存通过私有堆(Private Heap)机制分配,避免与 new / malloc 竞争同时又减少内存空洞。

伸缩性
  可以根据实际的使用环境要求设置组件的各项性能参数(如:工作线程的数量、各种缓存池的大小、收发缓冲区的大小、Socket 监听队列的大小、Accep 派发的数目以及心跳检查的间隔等)。
------------------------------------------------------------------------------------------------

*** v3.0.2 更新 ***

> 把 HP-Socket 编译为动态链接库:
-----------------
1、应用程序可以通过导入源代码或动态链接库方式使用 HP-Socket
2、动态链接库使用方法

方法一:
-----------------------------------------------------------------------
(0) 应用程序包含 SocketInterface.h 和 HPSocket.h 头文件
(1) 调用 HP_Create_Xxx() 函数创建 HPSocket 对象
(2) 使用完毕后调用 HP_Destroy_Xxx() 函数销毁 HPSocket 对象

方法二:
-----------------------------------------------------------------------
(0) 应用程序包含 SocketInterface.h 和 HPSocket.h 头文件
(1) 创建 CXxxWrapper 包装器,通过包装器智能指针使用 HPSocket 对象


3、动态链接库发行版本

(1) Bin/x86/HPSocket.dll - (32位/MBCS/Release)
(2) Bin/x86/HPSocket_D.dll - (32位/MBCS/DeBug)
(3) Bin/x86/HPSocket_U.dll - (32位/UNICODE/Release)
(4) Bin/x86/HPSocket_UD.dll - (32位/UNICODE/DeBug)
(5) Bin/x64/HPSocket.dll - (64位/MBCS/Release)
(6) Bin/x64/HPSocket_D.dll - (64位/MBCS/DeBug)
(7) Bin/x64/HPSocket_U.dll - (64位/UNICODE/Release)
(8) Bin/x64/HPSocket_UD.dll - (64位/UNICODE/DeBug)


> 其它更新:
-----------------
1、把组件接口以及监听器接口的声明移到 SocketInterface.h
2、IServer 增加接口方法 GetConnectionCount()/GetConnectPeriod() 分别获取当前连接数和某个连接的时长
3、IServer 接口方法 GetListenAddress()/GetClientAddress() 的 CString& 参数改为 LPTSTR
4、IClient 接口方法 GetLocalAddress() 的 CString& 参数改为 LPTSTR
5、SocketHelper.h 中所有全局函数的 CString& 参数均改为 LPTSTR
6、示例工程 TestEcho-Pull 和 TestEcho-PFM 改为用动态链接库方式使用 HP-Socket

> 升级说明:
-----------------
1、使用 HP-Socket v3.0.1 的应用程序可以安全升级到 HP-Socket v3.0.2
2、由于某些接口方法的参数作了调整,因此请参考测试工程作相应修改
3、如果工程想通过动态链接库方式使用 HP-Socket,请参考 TestEcho-Pull 或 TestEcho-PFM 示例工程
------------------------------------------------------------------------------------------------

*** v3.0.1 更新 ***

> 新增 UDP 通信组件:
-----------------
1、新增两个 UDP 通信组件:CUdpServer 为服务端组件,CUdpClient 为客户端组件
2、服务端组件 CUdpServer 采用 IOCP 通信模型
3、客户端组件 CUdpClient 采用 Event Select 通信模型
4、UDP 通信组件的接口与原 TCP 通信组件一致,简单实用
5、UDP 通信组件内置通信线路自动监测机制
6、新增 UDP 通信组件示例工程 TestEcho-UDP

> 代码重构与优化:
-----------------
1、规范所有接口、类以及代码文件的命名
2、重构和优化了大量组件代码
3、服务端组件加入读写锁机制,有效平衡处理性能与安全性
4、服务端组件的 Socket 对象缓存列表设置了锁定时间,提高访问的安全性
------------------------------------------------------------------------------------------------

*** v2.2.3 更新 ***

> 连接 ID 的数据类型改为‘CONNID’:
-----------------
1、在SocketHelper.h 中定义 CONNID 数据类型(默认:typedef ULONG_PTR CONNID)
2、应用程序可以把 CONNID 定义为其希望的类型(如:ULONG / ULONGLONG 等)
3、为了便于移植与维护,应用程序的任何地方都应该用‘CONNID’类型引用连接 ID

> 服务端 Socket 组件支持为每个连接绑定附加数据:
-----------------
1、IServerSocket 和 CIocpServer 增加方法 Get/SetConnectionExtra()
2、通过上述两个方法,应用程序可以为每个连接绑定任意附加数据并把数据获取出来
------------------------------------------------------------------------------------------------

*** v2.2.2 更新 ***

> 优化心跳检测相关功能:
-----------------
1、IServerSocket 和 IClientSocket 的 Get/SetKeepAliveTimes() 方法改为 Get/SetKeepAliveTime()
2、CIocpServer 和 CClientSocket 的默认 KeepAliveTime 属性改为 5000
3、CIocpServer 和 CClientSocket 的默认 KeepAliveInterval 属性改为 3000
------------------------------------------------------------------------------------------------

*** v2.2.1 更新 ***

> PULL 模型支持:
-----------------
1、ISocketListener 增加 PULL 模型数据接收通知方法 OnReceive(dwConnID, int)
2、增加 PULL Socket 接口 IPullSocket,该接口的 Fetch(dwConnID, pBuffer, iLength) 方法用于抓取通信数据

> Server:
-----------------
1、服务端 Socket 接口 ISocketServer 改名为 IServerSocket
2、增加 PULL Server Socket 监听器抽象类 CPullServerSocketListener
3、增加 PULL Server Socket 接口 IPullServerSocket
4、增加 PULL Server Socket 实现类 CIocpPullServer

> Client:
-----------------
1、客户端 Socket 接口 ISocketClient 改名为 IClientSocket
2、客户端 Socket 实现类 CSocketClient 改名为 CClientSocket
3、增加 PULL Client Socket 监听器抽象类 CPullClientSocketListener
4、增加 PULL Client Socket 接口 IPullClientSocket
5、增加 PULL Client Socket 实现类 CPullClientSocket
...全文
4613 91 打赏 收藏 转发到动态 举报
写回复
用AI写文章
91 条回复
切换为时间正序
请发表友善的回复…
发表回复
lobtao 2015-11-17
  • 打赏
  • 举报
回复
这么牛逼的socket库,最麻烦的问题就是解决这个。 我用Delphi的,希望比较容易使用。
苍原狮啸 2014-12-30
  • 打赏
  • 举报
回复
感谢楼主的热心分享,贵在坚持,加油
DuMiYue 2013-12-11
  • 打赏
  • 举报
回复
引用 74 楼 xi52qian 的回复:
这个必须的,要好好学习研究!最近刚刚自己写了一个类似的东西!对比一下我的差距!
欢迎试用 v3.1.1(Beta-1)
DuMiYue 2013-12-11
  • 打赏
  • 举报
回复
--> 注意 <-- 目前发布到是 Beta-1
DuMiYue 2013-12-11
  • 打赏
  • 举报
回复
(注:HP-Socket v3.1.1 的源代码依赖 vc-common-src-2.3.2.zip 中的基础公共代码。因此,编译 HP-Socket v3.1.1 时需要同时下载 vc-common-src-2.3.2.zip) =================================================== v3.1.1 更新: =================================================== (注:跳过 v3.0.3 版,将来会直接发布 v3.1.1 正式版) > 增加导出纯 C 函数的动态链接库 HPSocket4C.dll: ----------------- 1、增加代码文件 HPSocket4C.h 和 HPSocket4C.cpp,用于创建 HPSocket4C.dll 2、导出纯 C 函数,让其它语言(如:C/C#/Delphi 等)能方便地使用 HPSocket 3、HPSocket4C.dll 使用方法 方法一: -------------------------------------------------------------------------------------- (0) (C/C++ 程序)包含 HPSocket4C.h 头文件 (1) 调用 ::Create_HP_XxxListener() 函数创建监听器对象 (2) 调用 ::Create_HP_Xxx(pListener) 函数创建 HPSocket 对象 (3) 调用 ::HP_Set_FN_Xxx_OnYyy(pListener, ...) 函数设置监听器的回调函数 (4) 调用相关导出函数操作 HPSocket 对象 (5) ...... ...... (6) 调用 ::Destroy_HP_Xxx(pSocket) 函数销毁 HPSocket 对象 (7) 调用 ::Destroy_HP_XxxListener(pListener) 函数销毁监听器对象 方法二: -------------------------------------------------------------------------------------- (1) 应用程序把需要用到的导出函数封装到特定语言的包装类中 (2) 通过包装类封装后,以面向对象的方式使用 HPSocket 4、动态链接库发行版本 (1) x86/HPSocket4C.dll - (32位/MBCS/Release) (2) x86/HPSocket4C_D.dll - (32位/MBCS/DeBug) (3) x86/HPSocket4C_U.dll - (32位/UNICODE/Release) (4) x86/HPSocket4C_UD.dll - (32位/UNICODE/DeBug) (5) x64/HPSocket4C.dll - (64位/MBCS/Release) (6) x64/HPSocket4C_D.dll - (64位/MBCS/DeBug) (7) x64/HPSocket4C_U.dll - (64位/UNICODE/Release) (8) x64/HPSocket4C_UD.dll - (64位/UNICODE/DeBug) > 全面启用 Buffer Pool 缓存机制: ----------------- 1、Common/Src 增加代码文件 bufferpool.h 和 bufferpool.cpp,实现 Buffer Pool 缓存机制 2、通过 Buffer Pool 缓存机制提升内存使用效率,减少动态内存分配和释放操作,避免内存空洞 3、CTcpClient 用 CItemPool 和 TItemList 实现发送缓冲区 4、CUdpClient 用 CItemPool 和 TItemList 实现发送缓冲区 5、CTcpPullClient 用 CItemPool 和 TItemList 实现发送缓冲区和 PULL 缓冲区 6、CTcpPullServer 用 CBufferPool 和 TBuffer 实现 PULL 缓冲区 > 其它更新: ----------------- 1、增加代码文件 HPSocket4C.h 和 HPSocket4C.cpp,用于创建 HPSocket4C.dll 2、IServer 增加接口方法 DisconnectLongConnections() 用于断开所有超长连接 3、IClient 增加方法 Get/SetFreeBufferPoolSize()、Get/SetFreeBufferPoolHold() 用于设置 Buffer Pool 缓存大小和阀值 4、IServer 删除接口方法 GetConnectionCriSec() 5、IPullServer 删除方法 Get/SetFreePullBufferPool()、Get/SetFreePullBufferHold() 6、增加示例工程 TestEcho-4C,展示 HPSocket4C.dll 的使用方法 > 升级说明: ----------------- 1、使用 HP-Socket v3.0.2 及以前版本的应用程序可以安全升级到 HP-Socket v3.1.1 2、如果工程想通过导入 HPSocket4C.dll 的方式使用 HP-Socket,请参考 TestEcho-4C 示例工程
深山-蓝石头 2013-12-10
  • 打赏
  • 举报
回复
引用 85 楼 DuMiYue 的回复:
很简单嘛~~ 回调函数不是在主线程调用的。所以CALLBACK_SYNCRONOUS不行,而CALLBACK_ASYNCRONOUS_POST的话,异步执行回调函数时,参数可能已经被销毁了,容易造成崩溃,只能CALLBACK_ASYNCRONOUS_SEND了,但这样会阻塞工作线程,因此,最好取到数据后,回到函数立刻返回,交由其它线程处理数据。
嗯,这下明白了,谢谢!
DuMiYue 2013-12-09
  • 打赏
  • 举报
回复
引用 84 楼 ruan_peng 的回复:
CreateCallbackFunc(cCallback, cReturnType, cParamTypes [, oObject [, nFlags]]) nFlags: default = CALLBACK_SYNCRONOUS CALLBACK_SYNCRONOUS The C callback function is called on the main Visual FoxPro thread. For all Winapi functions e.g. EnumWindows. CALLBACK_ASYNCRONOUS_POST The C callback function is called on a seperate thread, for 3rd party C DLL's that raise events (call the C function). The callback itself is send asyncronously to the main Visual FoxPro thread, it does not block the 3rd party thread, the event is processed when FoxPro is in a READ EVENTS state. CALLBACK_ASYNCRONOUS_SEND The C callback function is called on a seperate thread, for 3rd party C DLL's that raise events (call the C function). The callback is send syncronously to the main Visual FoxPro thread, the thread resumes after the FoxPro function returns. CALLBACK_CDECL The C function uses the cdecl calling convention, by default the callback function is created with the stdcall calling convention. 不太明白意思,不过我将nFlag设为:CALLBACK_ASYNCRONOUS_SEND选项 ,那些崩溃事情没发生了 再次感谢!
很简单嘛~~ 回调函数不是在主线程调用的。所以CALLBACK_SYNCRONOUS不行,而CALLBACK_ASYNCRONOUS_POST的话,异步执行回调函数时,参数可能已经被销毁了,容易造成崩溃,只能CALLBACK_ASYNCRONOUS_SEND了,但这样会阻塞工作线程,因此,最好取到数据后,回到函数立刻返回,交由其它线程处理数据。
深山-蓝石头 2013-12-09
  • 打赏
  • 举报
回复
CreateCallbackFunc(cCallback, cReturnType, cParamTypes [, oObject [, nFlags]]) nFlags: default = CALLBACK_SYNCRONOUS CALLBACK_SYNCRONOUS The C callback function is called on the main Visual FoxPro thread. For all Winapi functions e.g. EnumWindows. CALLBACK_ASYNCRONOUS_POST The C callback function is called on a seperate thread, for 3rd party C DLL's that raise events (call the C function). The callback itself is send asyncronously to the main Visual FoxPro thread, it does not block the 3rd party thread, the event is processed when FoxPro is in a READ EVENTS state. CALLBACK_ASYNCRONOUS_SEND The C callback function is called on a seperate thread, for 3rd party C DLL's that raise events (call the C function). The callback is send syncronously to the main Visual FoxPro thread, the thread resumes after the FoxPro function returns. CALLBACK_CDECL The C function uses the cdecl calling convention, by default the callback function is created with the stdcall calling convention. 不太明白意思,不过我将nFlag设为:CALLBACK_ASYNCRONOUS_SEND选项 ,那些崩溃事情没发生了 再次感谢!
深山-蓝石头 2013-12-09
  • 打赏
  • 举报
回复
引用 82 楼 DuMiYue 的回复:
OnSend / OnReceive 参数是byte数组,不是字符串。。。
谢谢,事件终于可以成功回调了,是我CreateCallBackFunc参数选项没有弄对。
DuMiYue 2013-12-09
  • 打赏
  • 举报
回复
引用 79 楼 ruan_peng 的回复:
THIS.fnPrepareListen = CreateCallbackFunc('OnPrepareListen', 'INTEGER','LONG',THIS) THIS.fnAccept = CreateCallbackFunc('OnAccept', 'INTEGER','LONG,LONG',THIS) THIS.fnSend = CreateCallbackFunc('OnSend', 'INTEGER','LONG,STRING,LONG',THIS) THIS.fnReceive = CreateCallbackFunc('OnReceive', 'INTEGER','LONG,STRING,LONG',THIS) THIS.fnClose = CreateCallbackFunc('OnClose', 'INTEGER','LONG',THIS) THIS.fnError = CreateCallbackFunc('OnError', 'INTEGER','LONG,LONG,LONG',THIS) THIS.fnServerShutdown= CreateCallbackFunc('OnServerShutdown','INTEGER','',THIS) HP_Set_FN_Server_OnPrepareListen(This.pListener,This.fnPrepareListen) HP_Set_FN_Server_OnAccept(This.pListener,This.fnAccept) HP_Set_FN_Server_OnSend(This.pListener,This.fnSend) HP_Set_FN_Server_OnReceive(This.pListener,This.fnReceive) HP_Set_FN_Server_OnClose(This.pListener,This.fnClose) HP_Set_FN_Server_OnError(This.pListener,This.fnError) HP_Set_FN_Server_OnServerShutdown(This.pListener,This.fnServerShutdown)
OnSend / OnReceive 参数是byte数组,不是字符串。。。
深山-蓝石头 2013-12-09
  • 打赏
  • 举报
回复
如果我用 HPSocket4C_U.dll Server.Star() 直接 触发 OnServerShutdown 事件,而用HPSocket4C.dll 倒没有这种情况
深山-蓝石头 2013-12-09
  • 打赏
  • 举报
回复
&&&& 事件 &&&& FUNCTION OnPrepareListen(pListener) RETURN 0 ENDFUNC &&&& 事件 &&&& FUNCTION OnAccept(dwConnID,pSocket) RETURN 0 ENDFUNC &&&& 事件 &&&& FUNCTION OnSend(dwConnID,pData,iLength) RETURN 0 ENDFUNC FUNCTION OnReceive(dwConnID,pData,iLength) RETURN 0 ENDFUNC FUNCTION OnClose(dwConnID) RETURN 0 ENDFUNC &&&& 事件 &&&& FUNCTION OnError(dwConnID, enOperation, iErrorCode) *!* enOperation: *!* HP_SO_UNKNOWN = 0, // Unknown *!* HP_SO_ACCEPT = 1, // Acccept *!* HP_SO_CONNECT = 2, // Connnect *!* HP_SO_SEND = 3, // Send *!* HP_SO_RECEIVE = 4, // Receive RETURN 0 ENDFUNC &&&& 事件 &&&& FUNCTION OnServerShutdown RETURN 0 ENDFUNC
深山-蓝石头 2013-12-09
  • 打赏
  • 举报
回复
THIS.fnPrepareListen = CreateCallbackFunc('OnPrepareListen', 'INTEGER','LONG',THIS) THIS.fnAccept = CreateCallbackFunc('OnAccept', 'INTEGER','LONG,LONG',THIS) THIS.fnSend = CreateCallbackFunc('OnSend', 'INTEGER','LONG,STRING,LONG',THIS) THIS.fnReceive = CreateCallbackFunc('OnReceive', 'INTEGER','LONG,STRING,LONG',THIS) THIS.fnClose = CreateCallbackFunc('OnClose', 'INTEGER','LONG',THIS) THIS.fnError = CreateCallbackFunc('OnError', 'INTEGER','LONG,LONG,LONG',THIS) THIS.fnServerShutdown= CreateCallbackFunc('OnServerShutdown','INTEGER','',THIS) HP_Set_FN_Server_OnPrepareListen(This.pListener,This.fnPrepareListen) HP_Set_FN_Server_OnAccept(This.pListener,This.fnAccept) HP_Set_FN_Server_OnSend(This.pListener,This.fnSend) HP_Set_FN_Server_OnReceive(This.pListener,This.fnReceive) HP_Set_FN_Server_OnClose(This.pListener,This.fnClose) HP_Set_FN_Server_OnError(This.pListener,This.fnError) HP_Set_FN_Server_OnServerShutdown(This.pListener,This.fnServerShutdown)
DuMiYue 2013-12-09
  • 打赏
  • 举报
回复
引用 77 楼 camphor 的回复:
有Linux版本吗
恩。。。明年吧~~
camphor 2013-12-09
  • 打赏
  • 举报
回复
有Linux版本吗
DuMiYue 2013-12-09
  • 打赏
  • 举报
回复
引用 75 楼 ruan_peng 的回复:
VFP版封装类写好了,但使用存在问题:部分事件触发调回调函数,会致使程序崩溃 回调测试通过的事件有: Server.OnPrepareListen() Server.OnServerShutdown() Client.OnPrepareConnect() Client.OnConnect() 出现程序崩溃的事件有 Server.OnAccept() Server.OnReceive() Server.OnSend() Server.Close() Client.OnSend Client.OnReceive() Client.Close() //服务器端Disconnect出问题,客户端自己Stop没问题 我使用的是32位 HPSocket4C.dll,Tcp连接 不知道问题出在哪里
1、C# debug版本用HPSocket4C_UD.dll,release版本用HPSocket4C_U.dll 2、看现象是没有正确设置回调函数指针 3、OnError回调函数是必须设置的 4、如果用Pull模型需要设置OnPullReceive指针,否则需要设置OnReceive指针
深山-蓝石头 2013-12-09
  • 打赏
  • 举报
回复
VFP版封装类写好了,但使用存在问题:部分事件触发调回调函数,会致使程序崩溃 回调测试通过的事件有: Server.OnPrepareListen() Server.OnServerShutdown() Client.OnPrepareConnect() Client.OnConnect() 出现程序崩溃的事件有 Server.OnAccept() Server.OnReceive() Server.OnSend() Server.Close() Client.OnSend Client.OnReceive() Client.Close() //服务器端Disconnect出问题,客户端自己Stop没问题 我使用的是32位 HPSocket4C.dll,Tcp连接 不知道问题出在哪里
xi52qian 2013-12-09
  • 打赏
  • 举报
回复
这个必须的,要好好学习研究!最近刚刚自己写了一个类似的东西!对比一下我的差距!
DuMiYue 2013-12-07
  • 打赏
  • 举报
回复
引用 72 楼 ruan_peng 的回复:
[quote=引用 71 楼 DuMiYue 的回复:] [quote=引用 70 楼 ruan_peng 的回复:] 通用API版出来了,非常好, 顶!
你什么时候开始用起!?[/quote] 一个月前发现你写的这个,就很想用,一直不知怎样使用,因为不懂C++,还想找人将它封装成COM,方便在其它程序使用,上上版本封装成DLL后,很是高兴,但紧接着又是失望,还是不知道怎样用,直到你发布通用API后,燃起了我对它的激情,虽这第一个测试版32位有命名乱的问题,我用API函数查看器找到函数名后,还是可以用的,想不到第二版发布这么快就改正它了,非常感谢你的无私奉献! 现正在写VFP版封装类,还没开始用,期待一切顺利,早日让它发挥作用。[/quote] 欧耶~~~ 本月发布正式版,敬请期待~
深山-蓝石头 2013-12-06
  • 打赏
  • 举报
回复
通用API版出来了,非常好, 顶!
加载更多回复(70)

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧