Improve readme files and comments

This commit is contained in:
chenhaijian 2024-08-11 15:57:17 +08:00
parent f508c8bbd5
commit 5a33dbfc06
5 changed files with 87 additions and 33 deletions

View File

@ -31,3 +31,29 @@
* **TcpClientAcceptImpl.h/TcpClientAcceptImpl.cpp**实现了ITcpClientAccept接口处理客户端连接的接受和数据交换。 * **TcpClientAcceptImpl.h/TcpClientAcceptImpl.cpp**实现了ITcpClientAccept接口处理客户端连接的接受和数据交换。
# 一些易混淆的点
1. 客户端创建的套接字包含指定`目标的IP地址和端口号`TcpClientImpl类中的init函数服务器创建的套接字只包含`本机IP地址和监听端口`。
2. 在网络编程中,服务器通常会在一个监听端口上等待来自客户端的连接请求。当服务器接受到一个连接请求时,它会创建一个新的套接字(或文件描述符)来表示这个新建立的连接,并且通常会为这个新的连接设置一系列的事件回调函数。
3. 客户端实例TcpClientImpl类对象进行init操作时会创建一个套接字并对目标服务器发出连接请求并启动事件循环Loop函数然后客户端实例会一直进行事件循环监听是否有读写操作直至连接关闭Close函数
# 该模块的实现过程
## 服务器端:
1. 创建服务器端套接字:使用 hloop_create_tcp_server 函数创建一个新的 TCP 服务器端套接字,并指定要监听的 IP 地址和端口号。
2. 设置回调函数:为服务器端套接字设置回调函数,包括:
on_accept当有新的客户端尝试连接时调用。
on_close当服务器端套接字关闭时调用。
3. 启动事件循环:使用 hloop_run 启动服务器的事件循环,等待客户端的连接请求。
4. 接受连接:在 on_accept 回调函数中,接受客户端的连接请求,并创建用于该连接的新套接字。
5. 创建客户端接受对象:为新的客户端连接创建一个 TcpClientAcceptImpl 对象,并设置相应的回调函数。
管理客户端连接:将新创建的客户端接受对象添加到管理容器中,以便跟踪和管理。
## 客户端:
1. 创建客户端套接字:使用 hio_create_socket 函数创建一个新的 TCP 客户端套接字。
2. 设置回调函数:为客户端套接字设置回调函数,包括:
on_connect当连接成功建立时调用。
on_close当连接关闭时调用。
on_message当接收到服务器发送的数据时调用。
3. 连接到服务器:使用 hio_connect 函数向服务器发起连接请求。
4. 启动事件循环:使用 hloop_run 启动客户端的事件循环,等待连接结果和数据传输。
5. 处理连接结果:在 on_connect 回调函数中处理连接结果,如果连接成功,可以开始发送和接收数据。

View File

@ -26,7 +26,7 @@
/** /**
* @brief Called when data is received on a TCP connection. * @brief Called when data is received on a TCP connection.
* *
* @param io Socket handle * @param io Client's socket
* @param buf The transmitted data content * @param buf The transmitted data content
* @param len Byte length of transmitted data * @param len Byte length of transmitted data
*/ */
@ -38,17 +38,18 @@ static void on_message(hio_t *io, void *buf, int len)
} }
/** /**
* @brief Called when TCP connection is established. * @brief Called when TCP connection is established.
* @param io Socket handle * @param io Client's socket
*/ */
static void on_connect(hio_t *io) static void on_connect(hio_t *io)
{ {
LogInfo("onconnect: connfd=%d\n", hio_fd(io)); LogInfo("onconnect: connfd=%d\n", hio_fd(io));
hio_setcb_read(io, on_message); hio_setcb_read(io, on_message);
/// Start a read operation. Read data if it arrives.
hio_read(io); hio_read(io);
} }
/** /**
* @brief Called when tcp connection is disconnected. * @brief Called when tcp connection is disconnected.
* @param io Socket handle * @param io Client't socket
*/ */
static void on_close(hio_t *io) static void on_close(hio_t *io)
{ {
@ -60,8 +61,8 @@ TcpClientImpl::TcpClientImpl(const TcpClientParam &param, const void *object) :
{ {
} }
/** /**
* @brief Initialize TCP clients, create event loops, I/O objects, and set callback functions for connection and * @brief Create a socket and connect it, and start an event loop to listen to io object operations (read and write,
* closure. * etc.)
*/ */
void TcpClientImpl::Init(void) void TcpClientImpl::Init(void)
{ {
@ -72,6 +73,19 @@ void TcpClientImpl::Init(void)
LogError("TcpClientImpl::Init hloop_new failed.\n"); LogError("TcpClientImpl::Init hloop_new failed.\n");
return; return;
} }
/**
* @brief The client's socket, which is used to actively send connection requests to the server and handle related
* I/O operations, has no listening function.
* @param mLoop Event loop.
* When I/O events (connection closed, connection successful, data readable, etc.) occur, the event loop will call
* the corresponding callback function to handle them.
*
* @param mParam.mIp Server IP address
* @param mParam.mPort Server port
* @param HIO_TYPE_TCP TCP connection
* @param HIO_CLIENT_SIDE Indicates that the socket will be used as a client.
*
*/
hio_t *io = hio_create_socket(mLoop, mParam.mIp, mParam.mPort, HIO_TYPE_TCP, HIO_CLIENT_SIDE); hio_t *io = hio_create_socket(mLoop, mParam.mIp, mParam.mPort, HIO_TYPE_TCP, HIO_CLIENT_SIDE);
if (nullptr == io) { if (nullptr == io) {
LogError("TcpClientImpl::Init hio_create_socket failed.\n"); LogError("TcpClientImpl::Init hio_create_socket failed.\n");
@ -80,9 +94,9 @@ void TcpClientImpl::Init(void)
hevent_set_userdata(io, this); hevent_set_userdata(io, this);
/// Set the callback function of successful connection, and there is no connection operation. /// Set the callback function of successful connection, and there is no connection operation.
hio_setcb_connect(io, on_connect); hio_setcb_connect(io, on_connect);
/// Set the callback function to close the connection, and there is no connection operation.
hio_setcb_close(io, on_close); hio_setcb_close(io, on_close);
/// Connection operation hio_connect(io); ///< Connection operation
hio_connect(io);
mIo = io; mIo = io;
std::shared_ptr<TcpClientImpl> impl = std::dynamic_pointer_cast<TcpClientImpl>(shared_from_this()); std::shared_ptr<TcpClientImpl> impl = std::dynamic_pointer_cast<TcpClientImpl>(shared_from_this());
auto recvThread = [](std::shared_ptr<TcpClientImpl> tcpClient) { auto recvThread = [](std::shared_ptr<TcpClientImpl> tcpClient) {
@ -91,7 +105,7 @@ void TcpClientImpl::Init(void)
mTcpClientThread = std::thread(recvThread, impl); mTcpClientThread = std::thread(recvThread, impl);
} }
/** /**
* @brief De-initialize the TCP client, close the I/O object and wait for the receiving thread to end. * @brief De-initialize the TCP client, close the client't socket and wait for the event cycle to end.
*/ */
void TcpClientImpl::UnInit(void) void TcpClientImpl::UnInit(void)
{ {
@ -104,6 +118,12 @@ void TcpClientImpl::UnInit(void)
mTcpClientThread.join(); mTcpClientThread.join();
} }
} }
/**
* @brief Read the data sent by the server in tcp connection.
*
* @param data Data content sent by the server
* @param length Byte length of data content sent by the server.
*/
void TcpClientImpl::Readed(const void *data, size_t length) void TcpClientImpl::Readed(const void *data, size_t length)
{ {
if (nullptr != mParam.mReadFunc) { if (nullptr != mParam.mReadFunc) {
@ -112,6 +132,13 @@ void TcpClientImpl::Readed(const void *data, size_t length)
} }
LogError("mParam.mReadFunc is nullptr.\n"); LogError("mParam.mReadFunc is nullptr.\n");
} }
/**
* @brief The client writes data to the server, and the writing operation can only be performed in the connected state.
*
* @param buf Content of written data
* @param bufLenght Byte length of written data
* @return ssize_t
*/
ssize_t TcpClientImpl::Write(const void *buf, const size_t bufLenght) ssize_t TcpClientImpl::Write(const void *buf, const size_t bufLenght)
{ {
std::lock_guard<std::mutex> locker(mMutex); std::lock_guard<std::mutex> locker(mMutex);
@ -122,6 +149,10 @@ ssize_t TcpClientImpl::Write(const void *buf, const size_t bufLenght)
/// Returns the byte length of a packet.If it fails, an error code is returned. /// Returns the byte length of a packet.If it fails, an error code is returned.
return hio_write(mIo, buf, bufLenght); return hio_write(mIo, buf, bufLenght);
} }
/**
* @brief Close the tcp connection and stop the event loop (reading and writing I/O objects).
*
*/
void TcpClientImpl::Closed(void) void TcpClientImpl::Closed(void)
{ {
std::lock_guard<std::mutex> locker(mMutex); std::lock_guard<std::mutex> locker(mMutex);
@ -157,15 +188,12 @@ std::shared_ptr<ITcpClient> *NewTcpClient(const TcpClientParam &param)
return nullptr; return nullptr;
} }
TcpClient tmp; TcpClient tmp;
/// Initialize impl with tmp
memcpy((void *)impl, (void *)&tmp, sizeof(TcpClient)); memcpy((void *)impl, (void *)&tmp, sizeof(TcpClient));
impl->mHeader.mCheckName = GetTcpClientModuleName(); impl->mHeader.mCheckName = GetTcpClientModuleName();
/** /// ObjectThis is actually a pointer to mTcpClient in the TcpClient structure.
* @brief ObjectThis points to the first address of the impl and offsets the address by ITcpClientHeader bytes,
* that is, skips the mHeader part of the impl.
*/
std::shared_ptr<ITcpClient> *objectThis = std::shared_ptr<ITcpClient> *objectThis =
(std::shared_ptr<ITcpClient> *)(((char *)impl) + sizeof(ITcpClientHeader)); (std::shared_ptr<ITcpClient> *)(((char *)impl) + sizeof(ITcpClientHeader));
impl->mTcpClient = std::make_shared<TcpClientImpl>(param, objectThis); impl->mTcpClient = std::make_shared<TcpClientImpl>(param, objectThis);
/// ObjectThis is used to verify whether the client is legal.
return objectThis; return objectThis;
} }

View File

@ -27,20 +27,21 @@ class TcpClientImpl : public ITcpClient, public std::enable_shared_from_this<Tcp
public: public:
TcpClientImpl(const TcpClientParam &param, const void *object); TcpClientImpl(const TcpClientParam &param, const void *object);
virtual ~TcpClientImpl() = default; virtual ~TcpClientImpl() = default;
void Init(void) override; void Init(void) override; ///< Create a socket and connect it, and start an event loop to listen to io object
void UnInit(void) override; ///< operations (read and write, etc.)
void Readed(const void *data, size_t length) override; void UnInit(void) override; ///< close the client't socket and wait for the event cycle to end.
ssize_t Write(const void *buf, const size_t bufLenght) override; void Readed(const void *data, size_t length) override; ///< Read the data sent by the server in tcp connection.
void Closed(void) override; ssize_t Write(const void *buf, const size_t bufLenght) override; ///< client writes data to the server
void Closed(void) override; ///< Close the tcp connection and stop the event loop (reading and writing I/O objects).
void Loop(void); void Loop(void);
private: private:
std::mutex mMutex; /// A mutex lock used to synchronize access to shared resources. std::mutex mMutex; ///< A mutex lock used to synchronize access to shared resources.
hloop_t *mLoop; /// Event loop, listening for io objects hloop_t *mLoop; ///< Event loop, Listen for read/write or connection closing operations.
hio_t *mIo; /// Socket handle hio_t *mIo; ///< Client's socket
const TcpClientParam mParam; /// Basic information of the client, including port, ip, reading and closing. const TcpClientParam mParam; ///< Basic information of the client, including port, ip, reading and closing.
std::thread mTcpClientThread; std::thread mTcpClientThread; ///< A separate thread that runs an event loop to receive and process network data
const void *mObjectThis; /// ObjectThis is used to verify whether the client is legal. const void *mObjectThis; ///< ObjectThis is used to verify whether the client is legal.
}; };
std::shared_ptr<ITcpClient> *NewTcpClient(const TcpClientParam &param); std::shared_ptr<ITcpClient> *NewTcpClient(const TcpClientParam &param);
#endif #endif

View File

@ -25,9 +25,9 @@
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
/** /**
* @brief Disconnect the connected client. * @brief Handle the close connection event.
* *
* @param io Socket * @param io Server's socket
*/ */
static void on_close(hio_t *io) static void on_close(hio_t *io)
{ {
@ -150,15 +150,13 @@ TcpServerImpl::TcpServerImpl(const TcpServerParam param) : mParam(param)
void TcpServerImpl::Init(void) void TcpServerImpl::Init(void)
{ {
constexpr int NO_FALGS = 0; constexpr int NO_FALGS = 0;
/// Initialize event loop
/// mLoop is used to manage all I/O objects and the events that occur on them. /// mLoop is used to manage all I/O objects and the events that occur on them.
mLoop = hloop_new(NO_FALGS); mLoop = hloop_new(NO_FALGS);
if (nullptr == mLoop) { if (nullptr == mLoop) {
LogError("hloop_new failed\n"); LogError("hloop_new failed\n");
return; return;
} }
/// Create a listening event to listen whether a new client sends a connection request. /// Create a socket to listen whether a new client sends a connection request.
/// Listenio is part of mLoop.
hio_t *listenio = hloop_create_tcp_server(mLoop, mParam.mIp, mParam.mPort, on_accept); hio_t *listenio = hloop_create_tcp_server(mLoop, mParam.mIp, mParam.mPort, on_accept);
if (nullptr == listenio) { if (nullptr == listenio) {
LogError("hloop_create_tcp_server failed\n"); LogError("hloop_create_tcp_server failed\n");
@ -256,9 +254,9 @@ std::shared_ptr<ITcpClientAccept> *TcpServerImpl::GetClient(hio_t *io)
return nullptr; return nullptr;
} }
/** /**
* @brief Remove the data element in the map, that is, the connected client. * @brief Removes a specific connection from the list of client connections maintained by the server.
* *
* @param io Socket * @param io A server-side socket associated with an established client connection.
*/ */
void TcpServerImpl::RemoveClient(hio_t *io) void TcpServerImpl::RemoveClient(hio_t *io)
{ {
@ -316,6 +314,7 @@ std::shared_ptr<ITcpServer> *NewTcpServer(const TcpServerParam &param)
return nullptr; return nullptr;
} }
TcpServer tmp; TcpServer tmp;
/// Initialize impl with tmp
memcpy((void *)impl, (void *)&tmp, sizeof(TcpServer)); memcpy((void *)impl, (void *)&tmp, sizeof(TcpServer));
impl->mHeader.mCheckName = GetTcpServerModuleName(); impl->mHeader.mCheckName = GetTcpServerModuleName();
impl->mTcpServer = std::make_shared<TcpServerImpl>(param); impl->mTcpServer = std::make_shared<TcpServerImpl>(param);

View File

@ -54,7 +54,7 @@ public:
virtual ~TcpServerImpl() = default; virtual ~TcpServerImpl() = default;
void Init(void) override; void Init(void) override;
void UnInit(void) override; void UnInit(void) override;
void Loop(void); /// Run an event loop and release resources after completion or error. void Loop(void); /// Run an event loop and release resources after completion or error.
void AddClient(hio_t *io); void AddClient(hio_t *io);
std::shared_ptr<ITcpClientAccept> *GetClient(hio_t *io); std::shared_ptr<ITcpClientAccept> *GetClient(hio_t *io);
void RemoveClient(hio_t *io); /// Remove the data element in the map, that is, the connected client. void RemoveClient(hio_t *io); /// Remove the data element in the map, that is, the connected client.
@ -64,7 +64,7 @@ public:
private: private:
std::mutex mMutex; /// A mutex lock used to synchronize access to shared resources. std::mutex mMutex; /// A mutex lock used to synchronize access to shared resources.
hloop_t *mLoop; /// Event loop, listening for all io objects hloop_t *mLoop; /// Event loop, listening for all io objects
hio_t *mIo; /// listen whether a new client sends a connection request. hio_t *mIo; /// A server socket to listen whether a new client sends a connection request.
const TcpServerParam mParam; const TcpServerParam mParam;
std::thread mTcpServerThread; std::thread mTcpServerThread;
std::map<int, std::shared_ptr<ITcpClientAccept> *> mClients; std::map<int, std::shared_ptr<ITcpClientAccept> *> mClients;