一个管理监听、连接、发送、接收、组包的CSocket派生类

CSocket使用详解-MFC网络编程 MFC网络编程 阅读详情

简介:

    CAdmitSocket,从CSocket派生,它比CSocket增加的内容就是管理Accept后的Socket连接,重新定义Send函数。管理接收数据并组包,并在收到整包数据后,调用OnRecResponse(  LPBYTE, int )虚函数。

使用要点:

    你所使用的Socket必须从CAdmitSocket派生,并重载OnRecResponse()、OnSocketClose()。你可能需要重载OnAcceptSocket()。其中:

OnRecResponse()  : 当收到一个整包数据时,被调用。

OnAcceptSocket() :  表明一个客户连接已经被Accept。

OnSocketClose()   :  被接受的Socket已经关闭时,它和OnAcceptSocket()正好相反。

    你的派生类(假设为CMySocket)必须声明DECLARE_DYNCREATE(CMySocket)和IMPLEMENT_DYNCREATE(CMySocket,CAdmitSocket)。

    CPackHead是包头信息,其中字段:

            WORD    m_PackFlag;   //包标志,自定义的。

            UINT       m_PackSize;   //包长度,包括包头长度和数据长度

   如果你并不想要使用这个类,你也可以参照这个类的源代码,写你自己的Socket代码。

   附加:

   关于CSocket、CAsyncSocket使用的几点注意,否则将导致不必要的麻烦:
1、CSocket及其基类CAsyncSocket采用Windows消息机制,即Socket事件通过Post消息方式发往内建的窗口,并在该窗口内调用虚函数OnAccept()、OnConnect()、OnSend()、OnReceive()和OnClose()等,所以CSocket所在的线程必须要有消息循环。
2、一个CSocket对象要在多个线程里传递时,不能直接传递(指针)。因为CSocket被尽力设计为线程安全的,它的内部句柄m_hSocket同一时刻只能被一个线程拥有。因此,在线程间应该传递句柄而不是指针。方法是:当前拥有CSocket对象的线程先Detach(),然后将返回的句柄传给另一线程。在另一线程中,再Attach()。
3、CSocket在多线程中使用时,请对VS6.0打SP5。因为不打SP5和打SP5,AfxSockInit()函数的内部实现源代码是不同的。而后者则支持多线程。并且每个用到CSocket的线程,请都调用AfxSockInit()
4、对一次OnReceive()事件,请将Socket内部缓冲区的到达数据接收完,否则可能导致以后OnReceive()不再触发。原因是:OnSend()、OnReceive()都是当缓冲区从有到无或者从无到有数据才触发的。
5、Socket内部的默认缓冲区大小一般是4096或者8192,默认值大小特性是我们关注的,虽然不必要知道究竟有多大,但得知道有这么个特性,因此,除非是一应一答的通信,你应该在发送和接收时组包(包括自己定义包的边界和标志等信息)。

     头文件:AdmitSocket.h

#if !defined(AFX_ADMITSOCKET_H__68E0BD89_4E1E_48CB_B3E3_4235CED0C14B__INCLUDED_)
#define AFX_ADMITSOCKET_H__68E0BD89_4E1E_48CB_B3E3_4235CED0C14B__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <afxsock.h>
#include <afxtempl.h>

#ifdef _AFX_PACKING
#pragma pack(push, _AFX_PACKING)
#endif

//有关文件数据传输的Socket包结构和数据定义
#define   LISTENPORT1          3210   //Thales发送使用的Socket端口
#define   LISTENPORT2          3215   //和大调度通信的默认端口


typedef struct CPackHead {
 WORD    m_PackFlag;
 UINT    m_PackSize;
} CPackHead;

class CAdmitSocket : public CSocket
{
 DECLARE_DYNCREATE(CAdmitSocket)
public:
 CAdmitSocket();
 virtual ~CAdmitSocket();

 virtual void OnAcceptSocket( CAdmitSocket* pAcceptSock );
 virtual void OnSocketClose();
 virtual void OnRecResponse( LPBYTE, int );

 static CTypedPtrArray<CObArray,CAdmitSocket*>  s_SockArray;

 BOOL   Listen( int nPort = 0 );
 virtual void OnAccept(int nErrorCode);

 virtual void Close();

 BOOL    m_bListen;

 BOOL Connect( LPCTSTR lpszHostAddress, UINT nHostPort = 0 );
 BOOL Send( WORD nPackFlag, const void* lpBuf, int nBufLen );


public:
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CAdmitSocket)
 public: 
 virtual void OnReceive(int nErrorCode);
 virtual void OnClose(int nErrorCode);
 //}}AFX_VIRTUAL

 // Generated message map functions
 //{{AFX_MSG(CAdmitSocket)
  // NOTE - the ClassWizard will add and remove member functions here.
 //}}AFX_MSG

// Implementation
protected:
 UINT    m_nBufSize;
 LPBYTE  m_pRecDataBuf;
 UINT    m_nPrevDataSize;
// CPackHead  m_PackHead;
};

inline void CAdmitSocket::OnRecResponse( LPBYTE, int )
{
}

inline void CAdmitSocket::OnAcceptSocket( CAdmitSocket* pAcceptSock )
{
}

inline void CAdmitSocket::OnSocketClose()
{
}


#ifdef _AFX_PACKING
#pragma pack(pop)
#endif

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_ADMITSOCKET_H__68E0BD89_4E1E_48CB_B3E3_4235CED0C14B__INCLUDED_)

执行文件:AdmitSocket.cpp

#include "stdafx.h"
#include "AdmitSocket.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//#define  RECBUF_SIZE   10000

IMPLEMENT_DYNCREATE(CAdmitSocket, CSocket)

CTypedPtrArray<CObArray,CAdmitSocket*>  CAdmitSocket::s_SockArray;

CAdmitSocket::CAdmitSocket():m_pRecDataBuf(NULL),m_nPrevDataSize(0)
{
       m_bListen       = FALSE;
       m_nBufSize      = 0;
}

CAdmitSocket::~CAdmitSocket()
{
      if( m_hSocket != INVALID_SOCKET )
           CSocket::Close();
      if( m_pRecDataBuf != NULL )
     {
          delete []m_pRecDataBuf;
          m_pRecDataBuf = NULL;
     }
}


// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CAdmitSocket, CSocket)
 //{{AFX_MSG_MAP(CAdmitSocket)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif // 0

void CAdmitSocket::OnReceive(int nErrorCode)   //服务器方的接收
{
      if( nErrorCode != 0 )
     {
          ASSERT( FALSE );
          return;
     }

     int         nRec;
     DWORD       dwBytes = 0;
     CPackHead*  pPackHead;
     UINT        nOffset = 0, nHeadSize = sizeof( CPackHead );
     if( !IOCtl( FIONREAD, &dwBytes ) )
    {
         dwBytes = GetLastError();
         if( dwBytes == WSAENETDOWN || dwBytes == WSAENOTSOCK )
              Close();
         return;
    }
    if( dwBytes == 0 )
    {
        ASSERT( FALSE );
        return;
    }
    if( dwBytes+m_nPrevDataSize > m_nBufSize )
   {
        LPBYTE pTmpBuf = new BYTE[dwBytes+m_nPrevDataSize];
        if( m_pRecDataBuf != NULL )
       {
             memcpy( pTmpBuf, m_pRecDataBuf, m_nPrevDataSize );
             delete []m_pRecDataBuf;
        }
        m_pRecDataBuf = pTmpBuf;
        m_nBufSize    = dwBytes+m_nPrevDataSize;
   }
 nRec = Receive( m_pRecDataBuf + m_nPrevDataSize, dwBytes );
 if( nRec <= 0 )
 {
  Close();
  return;
 }
 m_nPrevDataSize += nRec;
 while( m_nPrevDataSize > nHeadSize )
 {
  pPackHead = (CPackHead*)(m_pRecDataBuf+nOffset);
  if( m_nPrevDataSize < pPackHead->m_PackSize )
   break;
  OnRecResponse( (LPBYTE)pPackHead, pPackHead->m_PackSize );
  m_nPrevDataSize -= pPackHead->m_PackSize;
  nOffset += pPackHead->m_PackSize;
 }
 if( nOffset > 0 && m_nPrevDataSize > 0 )
  memcpy( m_pRecDataBuf, m_pRecDataBuf+nOffset, m_nPrevDataSize );

 

 

/* if( nErrorCode != 0 )
 {
  ASSERT( FALSE );
  return;
 }

 TRACE( _T("OnReceive(),准备接收:/n") );
 int nPackSize, nHeadSize = sizeof( m_PackHead );
 int nRecCount = Receive( &m_PackHead, nHeadSize );
 if( nRecCount == 0 || nRecCount == SOCKET_ERROR )
 {
  Close();
  ASSERT( FALSE );
  return;
 }
 TRACE( _T("开始收到%d字节/n"), nRecCount );
 nPackSize = nRecCount;
 while( nPackSize < nHeadSize )
 {
  nRecCount = Receive( ((char*)(&m_PackHead))+nPackSize, nHeadSize-nPackSize );
  if( nRecCount == 0 || nRecCount == SOCKET_ERROR )
  {
   Close();
   ASSERT( FALSE );
   return;
  }
  nPackSize += nRecCount;
 }

 TRACE( _T("收到包头%d字节,总包长=%d/n"), nPackSize, m_PackHead.m_PackSize );

 LPBYTE pDataBuf = new BYTE[m_PackHead.m_PackSize];
 memcpy( pDataBuf, (char*)&m_PackHead, nHeadSize );
 while( (UINT)nPackSize < m_PackHead.m_PackSize )
 {
  nRecCount = Receive( pDataBuf + nPackSize, m_PackHead.m_PackSize - nPackSize );
  if( nRecCount == 0 || nRecCount == SOCKET_ERROR )
  {
   Close();
   ASSERT( FALSE );
   return;
  }
  nPackSize += nRecCount;
 }
 TRACE( _T("收到整包%d字节,进行处理!/n"), nPackSize );
 ASSERT( nPackSize == m_PackHead.m_PackSize );
 OnRecResponse( pDataBuf, m_PackHead.m_PackSize );
 delete []pDataBuf;
 DWORD dwBytes = 0;
 if( IOCtl( FIONREAD, &dwBytes ) && dwBytes > 0 )
 {
  TRACE( _T("Socket内部还有%d字节没有收,继续.../n"), dwBytes );
  OnReceive( 0 );
 }*/

/* if( nErrorCode != 0 )
  return;
 int     nPackSize, nRecCount;
 DWORD   nBytes = 0;
 if( m_nPrevDataSize == 0 )
 {
  CPackHead   phs;   
  int         nHeadSize = sizeof(phs);
  if( !IOCtl( FIONREAD, &nBytes ) || nBytes < (DWORD)nHeadSize ) //检查到达有多少字节
   return;
  nRecCount = Receive( &phs, nHeadSize, MSG_PEEK );
  if( nRecCount == 0 || nRecCount == SOCKET_ERROR ) //连接已经关闭
  {
   OnClose(0);
   return;
  }
  if( nRecCount != nHeadSize )  //不够包头长度
   return;

  nPackSize = phs.m_PackSize;
  if( m_pRecDataBuf == NULL )
   m_pRecDataBuf = (BYTE*)malloc( nPackSize );
  else
   m_pRecDataBuf = (BYTE*)realloc( m_pRecDataBuf, nPackSize );
 }
 else
 {
  nPackSize = ((CPackHead*)m_pRecDataBuf)->m_PackSize;
  if( m_nPrevDataSize >= nPackSize )  //永远也不应该出现这种情况
  {
   m_nPrevDataSize = 0;
   return;
  }
 }
 nRecCount = Receive( m_pRecDataBuf + m_nPrevDataSize, nPackSize - m_nPrevDataSize );
 if( nRecCount == 0 || nRecCount == SOCKET_ERROR ) //连接已经关闭
 {
  OnClose( 0 );
  return;
 }
 m_nPrevDataSize += nRecCount;
 if( m_nPrevDataSize == nPackSize )
 {
//  if( s_pProcRespSock != NULL )  //如果本Socket处于子线程里,那么下面的响应函数如果位于别的线程,这就需要进行线程同步
//   s_pProcRespSock( this, m_pRecDataBuf, nPackSize );
  OnRecResponse( m_pRecDataBuf, nPackSize );
  m_nPrevDataSize = 0;
  free( m_pRecDataBuf );
  m_pRecDataBuf = NULL;
  if( IOCtl( FIONREAD, &nBytes ) && nBytes > 0 )
   OnReceive( 0 );
 }*/
}

void CAdmitSocket::OnClose(int nErrorCode)
{
 Close();
}

BOOL CAdmitSocket::Listen( int nPort )
{
 if( nPort == 0 )
  nPort = LISTENPORT1;
 if( m_hSocket == INVALID_SOCKET && !Create( nPort ) )
  return FALSE;
 return (m_bListen = CSocket::Listen( 0x7fffffff ));
}

void CAdmitSocket::OnAccept(int nErrorCode)
{
 CAdmitSocket* psockit = (CAdmitSocket*)this->GetRuntimeClass()->CreateObject();
 ASSERT( psockit != NULL );
 if( !Accept( *psockit ) )
  delete psockit;
 s_SockArray.Add( psockit );
 OnAcceptSocket( psockit );
 CSocket::OnAccept( nErrorCode ); 
}

void CAdmitSocket::Close()
{
// DWORD nBytes = 0;
// IOCtl( FIONREAD, &nBytes );

 

 CSocket::Close();
 int i, nCount = s_SockArray.GetSize();
 if( m_bListen )
 {
  for( i=0; i<nCount; i++ )
  {
   delete s_SockArray[i];
  }
  s_SockArray.RemoveAll();
 }
 else
 {
  for( i=0; i<nCount; i++ )
  {
   if( s_SockArray[i] == this )
   {
    OnSocketClose();
    s_SockArray.RemoveAt( i );
    delete this;
    break;
   }
  }
 }
}

BOOL CAdmitSocket::Connect( LPCTSTR lpszHostAddress, UINT nHostPort )
{
 if( m_hSocket == INVALID_SOCKET && !Create() )
  return false;
 if( nHostPort == 0 )
  nHostPort = LISTENPORT1;
 if( !CSocket::Connect( lpszHostAddress, nHostPort ) )
 {
  if( GetLastError() != WSAEWOULDBLOCK )
   return FALSE;
 }
 return TRUE;
}

BOOL CAdmitSocket::Send( WORD nPackFlag, const void* lpBuf, int nBufLen )
{
/* CPackHead  ph;
 ASSERT( nBufLen > 0 );
 ph.m_PackFlag  = nPackFlag;
 ph.m_PackSize  = sizeof(ph) + ((UINT)nBufLen);
 if( CSocket::Send( &ph, sizeof(ph) ) == SOCKET_ERROR )
  return FALSE;
 if( nBufLen > 0 )
  return (CSocket::Send( lpBuf, nBufLen ) != SOCKET_ERROR);
 return TRUE;
*/
 int nHeadSize = sizeof(CPackHead);
 CPackHead* pPackHead;
 BYTE* lpSendBuf = new BYTE[nHeadSize+nBufLen];
 pPackHead = (CPackHead*)lpSendBuf;
 pPackHead->m_PackFlag = nPackFlag;
 pPackHead->m_PackSize = (UINT)(nHeadSize + nBufLen);
 if( nBufLen > 0 )
  CopyMemory( lpSendBuf+nHeadSize, lpBuf, nBufLen );
 if( CSocket::Send( lpSendBuf, pPackHead->m_PackSize ) == SOCKET_ERROR )
 {
  delete [] lpSendBuf;
  return FALSE;
 }
 delete [] lpSendBuf;
 return TRUE;
}

【项目】MFC下TCP/IP的套接字编程中CSocket,CSocketfile与CArchive类 CSocket类与CAsyncSocket类CAsyncSocket类编程模型  在一个MFC应用程序中,要想轻松处理多个网 络协议,而又不牺牲灵活性时,可以考虑使用CAsyncSocket类,它的效率比CSocket 类要高。CSocket类编程模型  使用CSocket对象涉及CArchive和CSocketFile 类对象。  以下介绍的针对字节流型套接字的操作步骤中,只有第3步对于客户方和服 阅读详情

相关推荐

MFC Socket接收不到数据的系统性排查与解决方案

Socket网络编程是构建客户端/服务器应用的基础技术,它通过操作系统提供的套接字接口实现进程间通信。其核心原理是在TCP/IP协议栈上建立连接、传输数据流。在Windows平台,MFC框架通过CAsyncSocket和CSocket类对原生WinSock API进行了面向对象封装,简化了异步事件处理和阻塞式调用,提升了开发效率。然而,这种封装也引入了特有的复杂性,尤其是在事件驱动模型、缓冲区管理和线程同步方面。当程序逻辑正确但Socket接收端却陷入沉默时,这通常不是单一故障,而是网络层、MFC事件机制与

weixin_33738555的博客 537

Socket 中级篇(四) TCP组包、粘包、拆包的原理

第一章、简介 1、这篇博客我想阐述什么? 在利用Socket+Tcp通信中,如果不采用开源库(比如SuperSocket)来实现,那么就是自己写了。既然自己写的东西,必须考虑稳定性、有效性、可行性等等。 直到今天,在用Socket/TCP做视频监控过程中,当网络较慢时,Socket/tcp通信,并不能一次性地把发送缓存区的数据发送出去。如果接受端不做处理,而是按接...

xpj8888的博客 8816

使用CSocket实现UDP编程的简洁教程

在构建网络通信应用时,了解各种网络协议及其特点至关重要。UDP(User Datagram Protocol,用户数据报协议)是一种无连接的网络协议,它允许数据包在网络中传输而不需要建立连接。UDP传输速度快,但不保证数据包的顺序和可靠性,因此适用于对实时性要求高而对准确性要求不高的应用场景。

weixin_42126677的博客 1088

Socket组包和分包快速理解及相关示例

socket 分包和组包:建议使用字节流。组包和拆包是一个近似序列化和反序列化的过程。 目录 组包 拆包 C++组包发送与拼包解析 组包拆包示例 消息形式为: 包长度(short)+包头(short)+messages(string)+包尾(short) 组包 组包的意思是按照协议构建二进制数组数据。 private void writesMessage(short cmd ,...

纸上得来终觉浅,绝知此事要躬行 4610

基于MFC的简易网络监听程序设计与实现

为了提高通信可靠性和扩展性,必须定义结构化的应用层协议。采用如下二进制协议格式:字段长度(字节)类型说明2uint16_t标识协议起始(如0xABCD)4int32_t负载长度(不含头)Command ID2uint16_t操作类型Checksum4uint32_tCRC32校验值PayloadNbyte[]实际数据。

weixin_29041443的博客 863

socket 图像分包 组包传输源码

用udp实现的图像传输程序,包含客户端和服务器端,用多线程支持多客户端。在服务端将图片分包,客户端用异步socke实现图片组包接收。测试通过,下载后服务端图片的地址需要自己更正!

CSOCKET的超时设置和UDP发送接收

    使用CSoket多次了,但对于它的block模式的理解并不是很深入。昨天使用csoket的udp多发测试(server接到数据后,需要通过某种方式将数据发送到client,使用tcp方式比较可靠,我一直这样用的,但是比较费时,需要逐一发送),发现了问题:  1)create(),sendto(),receivefrom()....  2)其中,发送方一直定时发送数据无问题; 

mrxwh的专栏 3412

一个Socket连接管理器

NULL 博文链接:https://cuisuqiang.iteye.com/blog/1489661

windows下网络编程(四)——MFC CSocket

CSocket类是CAsyncSocket类的派生类,它继承了windows socket API封装函数。实现了比CAsyncSocket类对windows socket更高层的抽象。它与类CSocketFile和CArchive共同合作完成对发送数据和接受数据的管理,CSocket类提供了对于同步操作CArchive对象非常重要的阻塞功能,是程序员在管理数据的发送和接收的工作变得简单。 CS

caowei880123的专栏 5259

VC编程实现使用CSocket进行有连接(TCP)通信

VC编程实现使用CSocket进行有连接(TCP)通信

CSocket 传文件 mfc VC6 我自己修改的 精简版

CSocket 传文件 mfc VC6 我自己修改的 精简版 一看就懂 呵呵 自己收藏的

[转]利用MFC的Csocket类实现网络通信

利用MFC的Csocket类实现网络通信Mail   近年来,利用Internet进行网际间通讯,在WWW浏 览、FTP、Gopher这些常规服务,以及在网络电话、多媒体会议等这些对实时性要求严格 的应用中成为研究的热点,而且已经是必需的了。Windows环境下进行通

Mobidogs Blog 1678

智能驾驶功能软件平台设计规范 第一部分:系统架构

智能驾驶功能软件平台设计规范 第一部分:系统架构2020-07-29 发布。

爱是与世界平行 6744

CSocket网络编程基础

CSocket类是CAsyncSocket类的派生类,它继承了Windows Socket API封装函数。它实现了比CAsyncSocket类对Windows Sockets更高层的抽象。它与CSocketFile类和CArchive类合作完成对数据的发送、接收的管理,并提供了对于同步操作CArchive对象非常重要的阻塞功能,使程序员在管理数据的发送和接收的工作变得简单。本篇只介绍如何使用CS

hellokazhang的博客 1006

Python 使用Pygame库实现足球游戏:创建一个球员和一个足球,并使玩家能够控制球员的移动。游戏将包括碰撞检测、简单的物理模拟,以及基本的用户输入处理

本文将介绍如何使用Python和Pygame库创建一个简单的足球游戏。我们将搭建一个基本的游戏环境,创建一个球员和一个足球,并使玩家能够控制球员的移动。游戏将包括碰撞检测、简单的物理模拟,以及基本的用户输入处理。这个简单的足球游戏展示了Pygame的一些基本功能。虽然这是一个简单的游戏,但它包含了创建游戏循环、用户输入处理、物理模拟、碰撞检测等重要概念。

程序熊的博客 743

nRF开发环境搭建全攻略:VS Code + nRF Connect SDK + Zephyr实战

嵌入式开发中,环境配置往往是新手入门的第一道障碍,尤其面对基于Zephyr RTOS的Nordic nRF平台时,工具链的复杂度常让人望而却步。理解构建系统、SDK版本管理和调试工具之间的协作关系,是高效开发的前提。Zephyr作为开源实时操作系统,通过设备树和Kconfig实现硬件描述与功能配置,而nRF Connect SDK(NCS)则是Nordic基于Zephyr的增强发行版,两者结合为物联网开发提供了强大支持。基于VS Code搭建开发环境,配合west工具管理多仓库、CMake/Ninja执行构

weixin_29188997的博客 227

利用MFC的Csocket类实现网络通信

利用MFC的Csocket类实现网络通信   近年来,利用Internet进行网际间通讯,在WWW浏 览、FTP、Gopher这些常规服务,以及在网络电话、多媒体会议等这些对实时性要求严格 的应用中成为研究的热点,而且已经是必需的了。Windows环境下进行通讯程序设计的最基本方法是应用Windows Sockets实现进程间的通讯,为此微软提供了大量基于Windows Sockets的通讯API

深之JohnChen的专栏 7482

OB4.X集群状态running但是oceanbase-ce is not running

自 V3.2.0 起,若 obd 设置了加密密钥,执行 display 命令输出的集群信息中,密码相关内容为加密状态。若需输出明文密码,可在命令中添加 --epk/–encryption-passkey 指定密钥用于验证。obd 运维的数据库,启停需要使用obd进行操作,停机时候没有使用obd会导致集群状态running但是oceanbase-ce is not running。查看集群中的租户时无租户反馈,警告oceanbase-ce is not running,但是查询集群状态明明是running。

qq961573863的博客 1213

CASyncSocket类和CSocket类编程

 本文主要讲解以下内容(1)CAsyncSocket类编程模式。(2)CSocket类编程模式。(3)CSocketFile类和CArchive类简介。  通过学习,可以掌握CAsyncSocket类和CSocket类的编程模式,了解CSocketFile类和CArchive类。CAsyncSocket类逐个封装了Winsock函数,以前介绍过的Winsock函数在CAsyncSocket类的成员函数中都可以找到它们对应的函数。一个CAsyncSocket对象就代表着一个Windows   Socket,使

guo693的专栏 1078

31、MSP430FR2355时钟系统与低功耗模式解析

本文详细解析了MSP430FR2355的时钟系统和低功耗模式。首先介绍了时钟系统的组成,包括XT1振荡器、DCO、MODCLK、MCLK、SMCLK和ACLK的功能与配置方法。接着探讨了MSP430FR2355的五种低功耗模式及其配置要点,并分析了时钟系统与低功耗模式之间的协同关系。最后通过实际应用案例展示了如何在具体场景中优化系统功耗。文章旨在帮助开发者充分利用MSP430FR2355的时钟与低功耗特性,实现高性能、低功耗的嵌入式系统设计。

mars5的博客 195

锂电池SOH预测 | 基于BP神经网络的锂电池SOH预测(附matlab完整源码)

锂电池SOH预测 | 基于BP神经网络的锂电池SOH预测(附matlab完整源码)

天天酷科研的博客 1114
上一篇: Socket API,CAsyncSocket,CSocket内幕及其用法
下一篇: 在 MVC Controller 中,不依靠定制路由,随心所欲地拦截请求和处理请求,想怎么输入输出都行.
jmcooler
博客等级 码龄24年 13粉丝 4原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值