//Filename: SockClass.hpp#ifndef SOCK_CLASS_HPP#define SOCK_CLASS_HPP#include <iostream>#include <winsock2.h>namespace sockClass{ void error_info(const char* s);}class WinsockAPI{ private: WSADATA wsaData;public: WinsockAPI(int low_byte = 2, int high_byte = 2); ~WinsockAPI(); void showVersion() const;};class BaseSock{ protected: int sockFD;public: BaseSock(); virtual ~BaseSock() = 0; const int& showSockFD() const;};class TCPListenSock: public BaseSock{ private: sockaddr_in listenSockAddr;public: TCPListenSock(unsigned short listen_port); ~TCPListenSock(); void TCPListen( int max_connection_requests = 10) const;};class TCPServerSock: public BaseSock{ private: sockaddr_in clientSockAddr;protected: char* preBuffer; int preBufferSize; mutable int preReceivedLength;public: TCPServerSock( const TCPListenSock& listen_sock, int pre_buffer_size = 32); virtual ~TCPServerSock(); int TCPReceive() const; int TCPSend(const char* send_data, const int& data_length) const;};#endif //SockClass.hpp
//Filename: SockClass.cpp#include "SockClass.hpp"//sockClassnamespace sockClass{ void error_info(const char* s){ std::cerr << s << std::endl; throw WSAGetLastError();}}//class WinsockAPIWinsockAPI::WinsockAPI(int low_byte, int high_byte){ const WORD wVersionRequested = MAKEWORD(low_byte, high_byte); int wsa_startup_err = WSAStartup(wVersionRequested, &wsaData); if (wsa_startup_err != 0) { std::cerr << "WSAStartup() failed." << std::endl; throw wsa_startup_err; }}WinsockAPI::~WinsockAPI(){ WSACleanup();}void WinsockAPI::showVersion() const{ std::cout << "The version of Winsock.dll is " << int(LOBYTE(wsaData.wVersion)) << "." << int(HIBYTE(wsaData.wVersion)) << "." << std::endl; return;}//class BaseSockBaseSock::BaseSock():sockFD(-1){}BaseSock::~BaseSock(){}const int& BaseSock::showSockFD() const{ return sockFD;}//class TCPListenSockTCPListenSock::TCPListenSock(unsigned short listen_port){ sockFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockFD < 0) { sockClass::error_info("socket() failed."); } memset(&listenSockAddr, 0, sizeof(listenSockAddr)); listenSockAddr.sin_family = AF_INET; listenSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); listenSockAddr.sin_port = htons(listen_port); if (bind( sockFD, (sockaddr*)&listenSockAddr, sizeof(listenSockAddr)) < 0) { sockClass::error_info("bind() failed."); }}TCPListenSock::~TCPListenSock(){ closesocket(sockFD);}void TCPListenSock::TCPListen( int max_connection_requests) const{ if (listen( sockFD, max_connection_requests) < 0) { sockClass::error_info("listen() failed."); }}//class TCPServerSockTCPServerSock::TCPServerSock( const TCPListenSock& listen_sock, int pre_buffer_size):preBufferSize(pre_buffer_size),preReceivedLength(0){ preBuffer = new char[preBufferSize]; int clientSockAddrLen = sizeof(clientSockAddr); sockFD = accept( listen_sock.showSockFD(), (sockaddr*)&clientSockAddr, &clientSockAddrLen); if (sockFD < 0) { sockClass::error_info("accept() failed."); } std::cout << "Client (IP: " << inet_ntoa(clientSockAddr.sin_addr) << ") conneted." << std::endl;}TCPServerSock::~TCPServerSock(){ delete [] preBuffer; closesocket(sockFD);}int TCPServerSock::TCPReceive() const{ preReceivedLength = recv( sockFD, preBuffer, preBufferSize, 0); if (preReceivedLength < 0) { sockClass::error_info("recv() failed."); } else if (preReceivedLength == 0) { std::cout << "Client has been disconnected.\n"; return 0; } return preReceivedLength;}int TCPServerSock::TCPSend(const char* send_data, const int& data_length) const{ if (data_length > preBufferSize) { throw "Data is too large, resize preBufferSize."; } int sent_length = send( sockFD, send_data, data_length, 0); if (sent_length < 0) { sockClass::error_info("send() failed."); } else if (sent_length != data_length) { sockClass::error_info("sent unexpected number of bytes."); } return sent_length;}
//Filename AppSock.hpp#ifndef APP_SOCK_HPP#define APP_SOCK_HPP#include "SockClass.hpp"class TCPEchoServer: public TCPServerSock{ public: TCPEchoServer( const TCPListenSock& listen_sock, int pre_buffer_size = 32); ~TCPEchoServer(); bool handEcho() const;};#endif //AppSock.hpp
//Filename: AppSock.cpp#include <string>#include "AppSock.hpp"TCPEchoServer::TCPEchoServer(const TCPListenSock& listen_sock, int pre_buffer_size):TCPServerSock(listen_sock, pre_buffer_size){}TCPEchoServer::~TCPEchoServer(){}bool TCPEchoServer::handEcho() const{ const std::string SHUTDOWN_CMD = "/shutdown"; while (TCPReceive() > 0) { std::string cmd(preBuffer, SHUTDOWN_CMD.size()); if (cmd == SHUTDOWN_CMD && preReceivedLength == SHUTDOWN_CMD.size()) { return false; } TCPSend(preBuffer, preReceivedLength); } return true;}
//Filename: main.cpp#include "SockClass.hpp"#include "AppSock.hpp"int TCP_echo_server(int argc, char* argv[]);int main(int argc, char* argv[]){ int mainRtn = 0; try { mainRtn =TCP_echo_server(argc, argv); } catch (const char* s) { perror(s); return 1; } catch (const int& err) { std::cerr << "Error: " << err << std::endl; return 1; } return mainRtn;}int TCP_echo_server(int argc, char* argv[]){ const unsigned short DEFAULT_PORT = 5000; unsigned short listen_port = DEFAULT_PORT; if (argc == 2 && atoi(argv[1]) > 0) { listen_port = atoi(argv[1]); } WinsockAPI winsockInfo; winsockInfo.showVersion(); TCPListenSock listen_sock(listen_port); listen_sock.TCPListen(); bool go_on = true; while (go_on){ TCPEchoServer echo_server(listen_sock); go_on = echo_server.handEcho(); } return 0;}