Encapsulation of socket s in Linux servers (object-oriented approach) - Learning Records
1. Communication between processes:
Local: Pipeline (PIPE), Named Pipeline (FIFO), Message Queuing, Shared Memory, Semaphore
Local/Network: Sockets
Sockets can not only communicate with different processes on a single machine, but also with different processes across the network. They can clearly distinguish the client from the server, and enable multiple clients to connect to the same server.
(The above ways of communicating between writing processes are just within my knowledge, as well as other ways of communicating and detailed descriptions. Please skip to the reference blog)
2. Triple identifies the process of the network
We know that the process ID can be used locally to identify a process, and there may be a conflict between the IDs of a process of two hosts in the network. It is clear that the process ID cannot identify a process in the network. In the TCP/I P protocol family,'I P address'uniquely identifies the host, while'Protocol+Port' in the transport layer uniquely identifies the host's process. Then, through a triple.(i P address, protocol, port) identifies the process in the network.
I P Address+Protocol+Port->Process
3. Socket server-side connection process
Create a socket with a socket, and a file descriptor similar to the process
Call bind to name the socket, which is an identifier that allows Linux to transfer a connection to a specific port to the correct server process
Call listen to start listening for client connections, and listen creates a queue to hold the client's incoming connections
When a client calls a connect connection and the server calls accept to receive a client connection, the server creates a new socket to communicate with the client
IV. Packaging Source Code
Since the project does not design a client, there is no connect ion for client socket encapsulation, etc. Check the reference blog if necessary
-
Factory class (responsible for creating and destroying socket objects)
Class declaration
#pragma once #include <sys/types.h> #include "Packs.h" class TcpServer; class TcpClient; class CSocketFactory //Factory class, responsible for service-side creation and destruction { public: static TcpClient* createSocket(); /* Create client socket */ static TcpServer* createServerSocket(int port, int max_cl); /* Create a server socket */ static int destroy(TcpClient* tcp_client); /* Destroy */ static int destroy(TcpServer* tcp_server); /* Destroy */ }; class TcpClient { public: virtual int send(PACKET_T* pack) = 0; virtual int receive(PACKET_T* pack) = 0; virtual int close() = 0; }; class TcpServer { public: virtual TcpClient* accept() = 0; /* Accept Connection, Return socket Communicating with End */ virtual void init_socket(int& port, int& max_cl) = 0; // Initialize socket virtual int close() = 0; /* Close server socket */ };
Class Definition
#include "CSocketFactory.h" #include "TcpClientImp.h" #include "TcpServerImp.h" #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <stdio.h> #include <arpa/inet.h> #include <iostream> TcpClient* CSocketFactory::createSocket() { TcpClientImp* cl = new TcpClientImp(); memset(&cl->address, 0, sizeof(sockaddr)); return cl; } TcpServer* CSocketFactory::createServerSocket(int port, int max_cl) { // Here the subclass object is returned to the symbol class object, but it still has the subclass content, so if you want to use it, you can strongly transfer the subclass type. TcpServerImp* sr = new TcpServerImp(); sr->init_socket(port, max_cl); return sr; } int CSocketFactory::destroy(TcpClient* tcp_client) { // Here the subclass object is returned to the symbol class object, but it still has the subclass content, so if you want to use it, you can strongly transfer the subclass type. TcpClient* cl = (TcpClientImp*)tcp_client; cl->close(); delete cl; return 0; } int CSocketFactory::destroy(TcpServer* tcp_server) { TcpServerImp* sr = (TcpServerImp*)tcp_server; sr->close(); delete(sr); return 0; }
-
socket server-side class
Class Definition
#pragma once #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include "CSocketFactory.h" #include "TcpClientImp.h" class TcpServerImp :public TcpServer { public: TcpServerImp(); public: TcpClient* accept(); bool create(); bool reuse_addr(); bool bind(int port); bool listen(int max_cl); void init_socket(int& port, int& max_cl); int get_fd(); void set_fd(int &fd); int close(); public: struct sockaddr_in address; private: int sock_fd; };
Class declaration
#include "TcpServerImp.h" #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <iostream> TcpServerImp::TcpServerImp() { this->sock_fd = 0; } TcpClient* TcpServerImp::accept() { TcpClientImp* cl = (TcpClientImp*)CSocketFactory::createSocket(); int addr_len = 0; int nfd = ::accept(sock_fd, &cl->address, (socklen_t*)&addr_len); if (nfd == -1) { delete(cl); perror("accept:"); return NULL; } cl->set_fd(nfd); return cl; } bool TcpServerImp::create() { //1. Set up a listening socket if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Create listenfd error:"); return false; } return true; } bool TcpServerImp::reuse_addr() { int opt = 1; int len = sizeof(opt); if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &opt, len) < 0) { perror("setsockopt error:"); ::close(sock_fd); return false; } return true; } bool TcpServerImp::bind(int port) { address.sin_family = AF_INET; address.sin_port = htons(port); address.sin_addr.s_addr = INADDR_ANY; // inet_addr(ip) socklen_t ser_len = sizeof(address); if (::bind(sock_fd, (const struct sockaddr*)&address, ser_len) == -1) { perror("Bind listen sokcet error:"); return false; } return true; } bool TcpServerImp::listen(int max_cl) { if (::listen(sock_fd, max_cl) < 0) { perror("listen failure:"); return false; } return true; } void TcpServerImp::init_socket(int &port, int &max_cl) { // socket establishment, monitoring, receiving connection, data sending and receiving if (create() == false) { perror("tcp client create error:"); delete(this); exit(-1); } if (reuse_addr() == false) { perror("tcp reuse address error:"); exit(-1); } if (bind(port) == false) { perror("tcp bind error"); this->close(); delete(this); exit(-1); } if (listen(max_cl) == false) { perror("tcp listen error:"); exit(-1); } std::cout << "tcp server create success" << std::endl; } int TcpServerImp::get_fd() { return sock_fd; } void TcpServerImp::set_fd(int &fd) { sock_fd = fd; } int TcpServerImp::close() { if (sock_fd > 0) { int res = ::close(sock_fd); if (res != 0) { perror("::close:"); return res; } else { sock_fd = -1; } } return 0; }
-
socket client class
Class declaration
#pragma once #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include "CSocketFactory.h" class TcpClientImp :public TcpClient { public: TcpClientImp(); public: int send(PACKET_T* pack); int receive(PACKET_T* pack); int get_fd(); void set_fd(int &fd); int close(); public: struct sockaddr address; private: int sock_fd; };
Class Definition
#include "TcpClientImp.h" #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <iostream> TcpClientImp::TcpClientImp() { sock_fd = 0; } int TcpClientImp::send(PACKET_T* pack) { int wsize = write(sock_fd, pack, sizeof(PACKET_T)); if (wsize == -1) { perror("Client send pack error;"); } return wsize; } int TcpClientImp::receive(PACKET_T* pack) { int rsize = read(sock_fd, pack, sizeof(PACKET_T)); if (rsize == -1) { perror("Client receive pack error;"); } return rsize; } int TcpClientImp::get_fd() { return sock_fd; } void TcpClientImp::set_fd(int& fd) { sock_fd = fd; } int TcpClientImp::close() { if (sock_fd > 0) { int res = ::close(sock_fd); if (res != 0) { perror("TcpClientImp::close"); return res; } else { sock_fd = -1; } } return 0; }
-
5. Reference Blog
https://blog.csdn.net/a987073381/article/details/52006729
https://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html
https://www.cnblogs.com/piepie/p/3857618.html