Mastering Network Library Layers: Session, Connection, Channel, and Socket
This article explains the hierarchical design of network libraries, detailing the roles of Session, Connection, Channel, and Socket layers, their interactions, code examples, and how they can be combined or extended for various backend services.
“For any problem in computer science, adding an indirect intermediate layer can solve it,” a principle that captures the essence of software architecture design.
Software architecture follows a strict hierarchical structure, from operating systems to applications and even hardware components.
1. Network Library Design Layers
Common network communication libraries can be divided into many layers based on functionality.
From business to technical, the layers are Session, Connection, Channel, and Socket.
Session belongs to the business layer; Connection, Channel, and Socket belong to the technical layer.
The following sections introduce the purpose of each layer.
Session Layer
The Session layer sits at the top and does not belong to the network framework itself; it records business state data and handles business logic. After processing, it relies on the Connection layer for data transmission.
Example interface of an IM service Session class:
typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;
typedef const TcpConnectionPtr& CTcpConnectionPtrR;
class ChatSession {
public:
ChatSession(CTcpConnectionPtrR conn, int sessionid);
virtual ~ChatSession();
int32_t GetSessionId() { return m_id; }
int32_t GetUserId() { return m_userinfo.userid; }
std::string GetUsername() { return m_userinfo.username; }
int32_t GetClientType() { return m_userinfo.clienttype; }
int32_t GetUserStatus() { return m_userinfo.status; }
void SendUserStatusChangeMsg(int32_t userid, int type, int status = 0);
private:
bool Process(CTcpConnectionPtrR conn, const char* inbuf, size_t buflength);
void OnHeartbeatResponse(CTcpConnectionPtrR conn);
// ... other callbacks ...
TcpConnectionPtr GetConnectionPtr() {
if (m_tmpConn.expired()) return NULL;
return m_tmpConn.lock();
}
void Send(int32_t cmd, int32_t seq, const std::string& data);
// ... other send overloads ...
int32_t m_id; // session id
OnlineUserInfo m_userinfo; // user info
int32_t m_seq; // packet sequence number
bool m_isLogin; // login state
std::weak_ptr<TcpConnection> m_tmpConn; // reference to Connection
};The Session object does not own the Connection object; it holds a std::weak_ptr to avoid lifetime management issues.
Connection Layer
The Connection layer is the top of the technical stack; each client connection corresponds to a Connection object that records various state information such as connection status, buffers, traffic, and addresses.
A Connection object also holds a Channel object and manages its lifetime.
Typical interface of a Connection object:
class TcpConnection {
public:
TcpConnection(EventLoop* loop, const std::string& name, int sockfd,
const InetAddress& localAddr, const InetAddress& peerAddr);
~TcpConnection();
const InetAddress& localAddress() const { return m_localAddr; }
const InetAddress& peerAddress() const { return m_peerAddr; }
bool connected() const { return m_state == kConnected; }
void send(const void* message, int len);
void send(const std::string& message);
void send(Buffer* message);
void shutdown();
void forceClose();
void setConnectionCallback(const ConnectionCallback& cb);
void setMessageCallback(const MessageCallback& cb);
void setCloseCallback(const CloseCallback& cb);
void setErrorCallback(const ErrorCallback& cb);
Buffer* getInputBuffer();
Buffer* getOutputBuffer();
private:
enum StateE { kDisconnected, kConnecting, kConnected, kDisconnecting };
void handleRead(Timestamp receiveTime);
void handleWrite();
void handleClose();
void handleError();
void sendInLoop(const std::string& message);
void sendInLoop(const void* message, size_t len);
void shutdownInLoop();
void forceCloseInLoop();
void setState(StateE s) { m_state = s; }
StateE m_state;
std::shared_ptr<Channel> m_spChannel;
const InetAddress m_localAddr;
const InetAddress m_peerAddr;
ConnectionCallback m_connectionCallback;
MessageCallback m_messageCallback;
CloseCallback m_closeCallback;
ErrorCallback m_errorCallback;
Buffer m_inputBuffer;
Buffer m_outputBuffer;
CFlowStatistics m_flowStatistics;
};Channel Layer
The Channel layer usually holds a socket handle and performs the actual data transmission. It records the events to monitor (read/write/error) and provides interfaces to enable or disable these events.
Typical Channel interface:
class Channel {
public:
Channel(EventLoop* loop, int fd);
~Channel();
void handleEvent(Timestamp receiveTime);
int fd() const;
int events() const;
void setRevents(int revt);
void addRevents(int revt);
void removeEvents();
bool isNoneEvent() const;
bool enableReading();
bool disableReading();
bool enableWriting();
bool disableWriting();
bool disableAll();
bool isWriting() const;
private:
const int m_fd; // monitored fd
int m_events; // events to monitor
int m_revents; // returned events
};Some libraries merge the Connection and Channel layers into a single layer depending on complexity.
Socket Layer
The Socket layer is usually a thin wrapper around OS socket functions to hide platform differences.
Example wrapper functions:
namespace sockets {
#ifdef WIN32
// Windows specific definitions
#else
typedef int SOCKET;
#endif
SOCKET createOrDie();
SOCKET createNonblockingOrDie();
void setNonBlockAndCloseOnExec(SOCKET sockfd);
void setReuseAddr(SOCKET sockfd, bool on);
void setReusePort(SOCKET sockfd, bool on);
int connect(SOCKET sockfd, const struct sockaddr_in& addr);
void bindOrDie(SOCKET sockfd, const struct sockaddr_in& addr);
void listenOrDie(SOCKET sockfd);
int accept(SOCKET sockfd, struct sockaddr_in* addr);
int32_t read(SOCKET sockfd, void* buf, int32_t count);
#ifndef WIN32
ssize_t readv(SOCKET sockfd, const struct iovec *iov, int iovcnt);
#endif
int32_t write(SOCKET sockfd, const void* buf, int32_t count);
void close(SOCKET sockfd);
void shutdownWrite(SOCKET sockfd);
// ... address conversion utilities ...
}In practice, a service may combine Connection and Channel, or omit the Socket layer entirely.
Server and Client Objects
A server typically uses a TcpServer object to manage multiple connections, while a client may use a TcpClient to manage connectors.
class TcpServer {
public:
using ThreadInitCallback = std::function<void(EventLoop*)>;
enum Option { kNoReusePort, kReusePort };
TcpServer(EventLoop* loop, const InetAddress& listenAddr,
const std::string& nameArg, Option option = kReusePort);
~TcpServer();
void addConnection(int sockfd, const InetAddress& peerAddr);
void removeConnection(const TcpConnection& conn);
private:
int m_nextConnId;
std::map<std::string, TcpConnectionPtr> m_connections;
};Session Management
Although each Session corresponds one‑to‑one with a Connection, a dedicated SessionManager or SessionFactory is often used to manage Session lifetimes outside the network framework.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Linux
Focused on sharing Linux/Unix content, covering fundamentals, system development, network programming, automation/operations, cloud computing, and related professional knowledge.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
