HPSocket

HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件、客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/C++、C#、Delphi、E(易语言)、Java、Python 等编程语言接口。HP-Socket 对通信层实现完全封装,应用程序不必关注通信层的任何细节;HP-Socket 提供基于事件通知模型的 API 接口,能非常简单高效地整合到新旧应用程序中。
HP-Socket的一些应用方向

HP-Socket不同于传统MVC框架,HP-Socket不仅可以用于TCP/UDP开发,同时还有更广阔的应用领域,例如即时通讯类、物联网、游戏、服务治理、其它跨平台服务器或者中间件,这无疑大大提高了程序开发者的视野。目前这些领域的程序开发者奇缺,如果想在通讯领域有自己的技术优势,不满足于每天的增删改查工作,或者想向架构师方向或者技术大牛的方向发展,HP-Socket都是非常值得学习的框架。建议开发者不仅会用,而且能基于HP-Socket开发出属于自己的开源项目,提升技能增加自己的影响力。

github:  GitHub - ldcsaa/HP-Socket: High Performance TCP/UDP/HTTP Communication Component

 看云:  序言 · HP-SOCKET · 看云


前言

官方DEMO提供很多应用实例,但大多是MFC程序,所以准备搭建个基础版的,方便以后扩展。demo采用HPSocket的Pack模式,这样我们只需要处理逻辑,而不需要考虑分包、组包、粘包等情况

开发

  1. Connect

    • Server端 Start() 后, 会进入 OnPrepareListen() ,可获取server端 Ip , port 。

      EnHandleResult JSocketServer::OnPrepareListen(ITcpServer* pSender, SOCKET soListen)
      {TCHAR szAddress[50];int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);USHORT usPort;pSender->GetListenAddress(szAddress, iAddressLen, usPort);if (m_prepare_listen != nullptr) {m_prepare_listen(szAddress, iAddressLen, usPort);}return HR_OK;
      }
    • Client端 Start()后,会进入OnConnectListen(),可获取Server端 ip ,port ,也可获取本地 ip ,port。 server端会进入 OnAccept() ,获取上线用户 connid , ip , port,

      Client:
      EnHandleResult JSocketClient::OnConnect(ITcpClient* pSender, CONNID dwConnID)
      {TCHAR szAddress[50];int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);USHORT usPort;pSender->GetLocalAddress(szAddress, iAddressLen, usPort);if (m_connect_listen != nullptr) {m_connect_listen(dwConnID, szAddress, iAddressLen, usPort);}return HR_OK;
      }Server:
      EnHandleResult JSocketServer::OnAccept(ITcpServer* pSender, CONNID dwConnID, SOCKET soClient)
      {BOOL bPass = TRUE;TCHAR szAddress[50];int iAddressLen = sizeof(szAddress) / sizeof(TCHAR);USHORT usPort;pSender->GetRemoteAddress(dwConnID, szAddress, iAddressLen, usPort);if (m_accepte_listen != nullptr) {m_accepte_listen(dwConnID, szAddress, iAddressLen, usPort, nullptr);}return bPass ? HR_OK : HR_ERROR;
      }
    • 这里有个问题,就是不知道 client 和 server 如何通过连接绑定额外数据(比如用户名,地址等信息),类似于 SetConnectionExtra() 和 GetConnectionExtra() 那种方式。我采用的办法是当server收到用户上线通知后,主动将用户的信息发送给client端,client端收到消息后,将绑定信息发送给server,server收到通知后,缓存到集合中,然后将在线的用户通过json的方式发送给client端。(这种方式感觉不是很合理,暂且这么做把,以后再优化,有小伙伴知道的,麻烦指导一二。)

      • client端: 接收 server端 用户信息和在线用户通知

        JSocketResult JSocketClientBus::OnReceiveListen(ULONG connid, const UCHAR* data, int bodyLen) {JPkgBodyByte* bodyInfo = (JPkgBodyByte*)data;JUserInfo srcUserInfo;JUserInfo desUserInfo;GetUserInfoByBodyInfo(bodyInfo, srcUserInfo, desUserInfo);/*当客户端连接服务端成功后,无法获取服务端中客户端的connid,所以客户端需要接受服务端的用户信息,即connid。服务端当接受 OnAccept 监听后 ,给客户端发送用户信息指令 ,客户端收到用户信息指令后,保存用户信息。最后发送消息给服务端,服务端接受后,更新本地该用户信息.(即Ip , Port , AliasName ...)*/if (bodyInfo->msg_data_type == MSG_USER_INFO_TYPE) {m_userInfo.usId = desUserInfo.usId;m_userInfo.usAddress = new char[20];lstrcpyA(m_userInfo.usAddress, desUserInfo.usAddress);m_userInfo.usPort = desUserInfo.usPort;m_userInfo.usName = new char[strlen(m_aliasName) * sizeof(char)];lstrcpyA(m_userInfo.usName, m_aliasName);m_userInfo.usState = ONLINE_STATUS;/*    给服务端发送用户指令, 更新 AliasName */std::wstring s = L"updateUser";if (!SendMsgInfo(bodyInfo->msg_data_type, &m_userInfo, const_cast<wchar_t*>(s.c_str()), s.length())) {
        #if IS_LOGJSocketHelper::LogMsg("Client OnReceiveListen", m_userInfo,  "发送用户信息给server失败.", GetUserLastErrorCode());
        #endif // IS_TOAST}if (m_connectAPIListen != nullptr) {m_connectAPIListen(&m_userInfo);}return JResult_OK;}// 获取用户列表if (bodyInfo->msg_data_type == MSG_USER_LIST_TYPE) {if (m_receiveAPIListen != nullptr) {m_receiveAPIListen(bodyInfo->msg_data_type, &srcUserInfo, &desUserInfo, bodyInfo->desc, bodyInfo->desLen);}return JResult_OK;}if (bodyInfo->msg_data_type == MSG_INFO_TYPE) {if (m_receiveAPIListen != nullptr) {m_receiveAPIListen(bodyInfo->msg_data_type, &srcUserInfo, &desUserInfo, bodyInfo->desc, bodyInfo->desLen);}return JResult_OK;}if (bodyInfo->msg_data_type == MSG_USER_ONLINE_TYPE || bodyInfo->msg_data_type == MSG_USER_OFFLINE_TYPE) {/*    有终端上线 */if (bodyInfo->msg_data_type == MSG_USER_ONLINE_TYPE && m_acceptAPIListen != nullptr) {m_acceptAPIListen(&srcUserInfo);return JResult_OK;}/*   有终端下线 */if (bodyInfo->msg_data_type == MSG_USER_OFFLINE_TYPE && m_closeAPIListen != nullptr) {m_closeAPIListen(&srcUserInfo);return JResult_OK;}return JResult_OK;}return JResult_OK;
        }
      • server端:

        • 收到client端发送的用户信息后,将在线用户信息通过json方式发送给client端

        • 将用户信息发送给别的client端,通知该用户上线了。

        • 将用户信息缓存到集合中。

          JSocketResult JSocketServerBus::OnReceiveListen(ULONG connid, const UCHAR* data, int bodyLen) {JPkgBodyByte* bodyInfo = (JPkgBodyByte*)data;JUserInfo srcUserInfo;JUserInfo desUserInfo;GetUserInfoByBodyInfo(bodyInfo, srcUserInfo, desUserInfo);/* 更新用户信息 (connid, ip, port, AliasName ..)*/if (bodyInfo->msg_data_type == MSG_USER_INFO_TYPE) {m_user_collection.push_back(srcUserInfo);#if IS_LOGJSocketHelper::LogMsg("Server OnReceiveListen", srcUserInfo, "用户上线.", GetUserLastErrorCode());
          #endif // IS_TOASTif (m_acceptAPIListen != nullptr) {m_acceptAPIListen(&srcUserInfo);}// 通知用户上线post_user_info_to_users(MSG_USER_ONLINE_TYPE, srcUserInfo, "online");// 发送用户列表post_users_list_to_user(srcUserInfo);return JResult_OK;}// 发送消息if (bodyInfo->msg_data_type == MSG_INFO_TYPE) {if (!m_pSocketServer->SendMsg(desUserInfo.usId, (BYTE*)data, bodyLen)) {
          #if IS_LOGJSocketHelper::LogMsg("Server OnReceiveListen", srcUserInfo, desUserInfo, bodyInfo->desc, "转发消息失败.", GetUserLastErrorCode());
          #endif // IS_TOAST}if (m_receiveAPIListen != nullptr) {m_receiveAPIListen(bodyInfo->msg_data_type, &srcUserInfo, &desUserInfo, bodyInfo->desc, bodyInfo->desLen);}}return JResult_OK;
          }
  2. Send

    1. client端发送消息给server端,server端收到消息后,转发给接受的client端。

      client:
      // msg_data_type: 收发消息类型 desUser:接受者信息 msg:内容(UTF-8 byte[])
      bool JSocketBusBase::SendMsgInfo(int msg_data_type, JUserInfo *desUser, wchar_t* msg, int len) {int bodyLen;JPkgBodyByte* info = JSocketHelper::GetMsgBodyInfo(msg_data_type, &m_userInfo, desUser, msg, len, bodyLen);bool flag = Get()->SendMsg(desUser->usId, (BYTE*)info, bodyLen);if (!flag) {
      #if IS_LOGJSocketHelper::LogMsg("Base SendMsgInfo", m_userInfo, *desUser, msg, "转发信息失败.", GetUserLastErrorCode());
      #endif // IS_LOG}free(info);return flag;
      }server:
      // 根据connid,转发消息
      JSocketResult JSocketServerBus::OnReceiveListen(ULONG connid, const UCHAR* data, int bodyLen) {JPkgBodyByte* bodyInfo = (JPkgBodyByte*)data;JUserInfo srcUserInfo;JUserInfo desUserInfo;GetUserInfoByBodyInfo(bodyInfo, srcUserInfo, desUserInfo);// 发送消息if (bodyInfo->msg_data_type == MSG_INFO_TYPE) {if (!m_pSocketServer->SendMsg(desUserInfo.usId, (BYTE*)data, bodyLen)) {
      #if IS_LOGJSocketHelper::LogMsg("Server OnReceiveListen", srcUserInfo, desUserInfo, bodyInfo->desc, "转发消息失败.", GetUserLastErrorCode());
      #endif // IS_LOG}if (m_receiveAPIListen != nullptr) {m_receiveAPIListen(bodyInfo->msg_data_type, &srcUserInfo, &desUserInfo, bodyInfo->desc, bodyInfo->desLen);}}return JResult_OK;
      }
  3. DisConnect

    1. client端断开连接,server端在OnCloseListen()接受消息后,通知其他client端,该用户下线,并删除用户信息。client端在OnClose中接受到消息后,我在业务逻辑层中,回调了shutDown,我想的是和server端做到统一。实际client端没有shutDown回调。

      JSocketResult JSocketServerBus::OnCloseListen(ULONG connid) {JUserInfo user;BOOL flag = get_user_info_with_collection(connid, true, user);
      #if IS_LOGJSocketHelper::LogMsg("Server OnCloseListen", user, "用户下线.", GetUserLastErrorCode());
      #endif // IS_TOAST// 给用户发送下线通知if (flag) {post_user_info_to_users(MSG_USER_OFFLINE_TYPE, user, "offline");}else {// 缓存中没有id(todo)user.usId = connid;post_user_info_to_users(MSG_USER_OFFLINE_TYPE, user, "offline");}if (m_closeAPIListen != nullptr) {m_closeAPIListen(&user);}return JResult_OK;
      }
    2. server端断开连接后,会在OnShutdownListen中接受到消息,其实不光是主动断开连接,异常断线,比如网络异常等情况也会进入此回调函数中。所以我在这个回调中增加了自动重连,也就是当用户非主动断开连接,则会自动重连。同理,client端也是如此。

      client:
      JSocketResult JSocketClientBus::OnCloseListen(ULONG connid) {// 正在重连中。。if (m_enState == EN_RECONNECTING)return JResult_OK;if (m_shutDownAPIListen != nullptr) {m_shutDownAPIListen();}// 主动断开连接,不进行自动重连..if (m_enState == EN_STOPPED || m_enState == EN_STOPPING)return JResult_OK;clear();reconnect();return JResult_OK;
      }server:
      JSocketResult JSocketServerBus::OnShutdownListen() {// 正在重连中。。if (m_enState == EN_RECONNECTING)return JResult_OK;if (m_shutDownAPIListen != nullptr) {m_shutDownAPIListen();}if (m_enState == EN_STOPPED || m_enState == EN_STOPPING)return JResult_OK;clear();reconnect();return JResult_OK;
      }
  4. Other

    1. 设置一些基础的属性设置接口和辅助函数,比如SetMaxPackSize、SetPackHeaderFlag、SetKeepAliveTime、SetKeepAliveTimeInterval、GetLastError等等,官方demo中都有详细的介绍。
  5. DLL 接口

    1. dll 接口中参考官方demo也设置了对应的回调函数,但调整了几个,具体如下:
    2. 主要想的是 client 和 server 端 保持统一。
client:    /* client端 连接成功通知 */typedef void(*JSocketOnConnectListener)(JUserInfo *userAPI);/* client端 接受用户上线通知 */typedef void(*JSocketOnAcceptListener)(JUserInfo *server);/* client端 接受消息通知 srcUser:发送者 desUser:接受者 info:信息 */typedef void(*JSocketOnReceiveListener)(int msg_data_type, JUserInfo *srcUser, JUserInfo *desUser, wchar_t *info, int len);/* client端 已发送消息通知*/typedef void(*JSocketOnSendListener)(JUserInfo *body, wchar_t *info, int len);/* client端 用户下线通知 */typedef void(*JSocketOnCloseListener)(JUserInfo *user);/* client端 断开连接通知 */typedef void(*JSocketOnShutDownListener)();server:    /* server端 连接成功通知 */typedef void(*JSocketOnPrepareListener)(JUserInfo *server);/* server端 接受用户上线通知 */typedef void(*JSocketOnAcceptListener)(JUserInfo *server);/* server端 接受消息通知 srcUser:发送者 desUser:接受者 info:信息 */typedef void(*JSocketOnReceiveListener)(int msg_data_type, JUserInfo *srcUser, JUserInfo *desUser, wchar_t *info, int len);/* server端 用户下线通知 */typedef void(*JSocketOnCloseListener)(JUserInfo *user);/* server端 断开连接通知 */typedef void(*JSocketOnShutDownListener)();

C# demo程序 + C++ DLL

效果:

      

地址: https://download.csdn.net/download/haiyangyunbao813/14999630


END

  1. 以上内容就基本搭建好了一个基础版本的socket通讯,等以后实际落地应用在慢慢扩展,有需要的小伙伴可以参考参考。

  2. 此程序么有怎么测试过,也没有落地实际应用过,只是我简单的测试了一下,所以说肯定会有很多潜在bug,以及不足的地方,所以说各位大神,大佬们,有啥问题请及时指正,非常感谢。

  3. 最后还有一个星期就过年了,在此祝各位小伙伴们新年快乐。

基于 HPSocket , 实现 socket 通讯相关推荐

  1. 基于TCP的Socket通讯

    基于 TCP 的 Socket 通讯 最近要实现两个机器之间基于 TCP 的 socket 通讯(个人使用 Python 实现),尝试了官方的 demo 代码后总是被拒绝连接,仔细研究了一下并成功建立 ...

  2. QT示例:基于TCP点对点Socket通讯

    QT示例:基于TCP点对点通讯 一. 概述 二.TCP 协议工作原理 三.TCP 编程模型 四.基于TCP点对点通讯示例 1.客户端 2.客户端Client示例 3.服务器 4.服务器server示例 ...

  3. QT示例:基于TCP 点对多Socket通讯(server,clients)

    QT示例:基于TCP 点对多通讯(server,clients) 一.服务器server 二.客户端Client 下载:基于TCP 点对多Socket通讯 一.服务器server 因为对于客户端来说, ...

  4. Socket网络通讯开发总结之:Java 与 C进行Socket通讯

    先交待一下业务应用背景: 服务端:移动交费系统:基于C语言的Unix系统 客户端:增值服务系统:基于Java的软件系统 通迅协议:采用TCP/IP协议,使用TCP以异步方式接入 数据传输:基于Sock ...

  5. 试解析Tomcat运行原理(一)--- socket通讯(转)

    关于这篇文章也确实筹划了很久,今天决定开篇写第一篇,说起tomcat首先很容易联想到IIS,因为我最开始使用的就是.net技术,我第一次使用asp写学生成绩管理系统后,很茫然如何让别人都能看到或者说使 ...

  6. C#.net同步异步SOCKET通讯和多线程总结(转)

    C#.net同步异步SOCKET通讯和多线程总结 来源:http://www.cnblogs.com/Silverlight_Team/archive/2009/03/13/1411136.html ...

  7. 跨平台(windows+linux)的线程辅助程序,跨平台(Windows+Linux)的Socket通讯程序(二)—结构...

    上一篇"跨平台(Windows+Linux)的Socket通讯程序"给出了Socket通讯底层的一些函数的包装方法/类,同时屏蔽了操作系统(Windows/Linux)的不同. 上 ...

  8. api有哪些 javasocket_基于java的socket编程及API解析

    一.socket通讯过程 1.socket与socket编程简介: socket 被翻译为"套接字",它是计算机之间进行通信的一种约定或一种方式.通过 socket 这种约定,一台 ...

  9. 试解析Tomcat运行原理(一)--- socket通讯

    关于这篇文章也确实筹划了很久,今天决定开篇写第一篇,说起tomcat首先很容易联想到IIS,因为我最开始使用的就是.net技术,我第一次使用asp写学生成绩管理系统后,很茫然如何让别人都能看到或者说使 ...

  10. socket网络编程 java_Java Web 基础(一) 基于TCP的Socket网络编程

    一.Socket简单介绍 Socket通信作为Java网络通讯的基础内容,集中了异常.I/O流模式等众多知识点.学习Socket通信,既能够了解真正的网络通讯原理,也能够增强对I/O流模式的理解. 1 ...

最新文章

  1. Qt实用技巧:使用OpenCV库的视频播放器(支持播放器操作,如暂停、恢复、停止、时间、进度条拽托等...
  2. ASCII,Unicode和UTF-8终于找到一个能完全搞清楚的文章了
  3. HTML5中的CSS Shader技术
  4. jdk动态代理源码分析(一)---代理的定义
  5. MFC之CString与const char* string 转换
  6. 阿里发力线下渠道,腾讯京东该如何打破其流量优势?
  7. webpack原理和优化
  8. 权限丢失_应用好深圳RFID智能档案密集架,杜绝档案丢失!
  9. mysql5.7.23安装详细过程
  10. 谈一下对VUE生命周期的理解
  11. 精心挑选的100多种机器学习数据集
  12. uni-app自定义配置安卓模拟器 - MuMu模拟器
  13. 计算机DNS怎么配置,dns设置,教您怎么设置dns地址
  14. python中的魔法方法__new___Python魔法方法会调用new方法吗?
  15. linux进程cpu时间片,Linux性能监控之CPU篇
  16. Win 10 任务栏中Google开启时出现两个Google图标
  17. 学习信奥要不要先学python
  18. 基于jsp+mysql+Spring+SpringMVC+mybatis的ssm生鲜超市进销存管理系统
  19. 按光在光纤中的传输模式可将光纤分为单模光纤和多模光纤两种
  20. 打造智慧工地,低代码平台助力基建行业全链路数字化升级

热门文章

  1. 网络对战五子棋(web-gobang)项目
  2. 医药行业gsp药店管理软件哪个好用?
  3. 逻辑学是计算机科学的一个重要分支,逻辑学在计算机科学中应用.doc
  4. 重磅!公安部再度认可电子签名、电子印章法律效力!
  5. 亲历2010中国移动开发者大会
  6. 教程:批量自动删除微博
  7. VS2013 下载地址
  8. linux运维阿铭,阿铭Linux
  9. mmd动作:Fukayomi
  10. 英中繁简编程术语对照