├── README.md ├── include ├── SocketClient.h └── SocketServer.h ├── library └── libSocket.a ├── main_client.cpp ├── main_server.cpp └── src ├── SocketClient.cpp └── SocketServer.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Why 2 | Native socket implementation in C++ is... how to say... A TOTAL BRAINF***. If you never tryed to use them, don't try now! 3 | SocketClient allows easy communication between sockets and implements a callback pattern for receiving messages! 4 | 5 | # Callback Pattern 6 | The SocketClient class implements a callback pattern which is very usefull to handle messages and catch errors easily. 7 | 8 | For those who don't know: A callback is a function called when a specific event happen in the system. In this case, the callback will be called for every incoming message through the socket. You don't have to care about receiving messages, you are automatically 9 | alerted when you receive something. 10 | 11 | # Sample 12 | 13 | I made a simple Server/Client connection for the example: The Client connects to the server and can send as many messages as he wants. 14 | The Server implements the callback functions and displays the messages. 15 | 16 | Server: https://github.com/omaflak/Asynchronous-Socket-Class-C-Windows/blob/master/main_server.cpp 17 | 18 | Client: https://github.com/omaflak/Asynchronous-Socket-Class-C-Windows/blob/master/main_client.cpp 19 | 20 | # Compilation 21 | 22 | g++ main_client.cpp -o client.exe libSocket.a "C:\path\to\lib\libws2_32.a" 23 | g++ main_server.cpp -o server.exe libSocket.a "C:\path\to\lib\libws2_32.a" 24 | 25 | SocketClient.h and SocketServer.h must be with YOUR .cpp files, i.e in the same folder. 26 | 27 | # Tutorial 28 | 29 | For more explanations about the installation, please visit my website: https://causeyourestuck.io/2016/02/21/socket-library-c/ 30 | -------------------------------------------------------------------------------- /include/SocketClient.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKETCLIENT_H 2 | #define SOCKETCLIENT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | struct messageStruct; 10 | struct errorStruct; 11 | 12 | class SocketClient 13 | { 14 | public: 15 | SocketClient(std::string ip, int port); 16 | SocketClient(SOCKET socket); 17 | SocketClient(); 18 | 19 | int connect(); 20 | void close(); 21 | void send(std::string message); 22 | void send(std::istream &stream); 23 | std::string receive(); 24 | void setSize_of_packages(unsigned int n); 25 | void setBytes_for_package_size(unsigned int n); 26 | void setMessageCallback(void (*callback_function)(messageStruct *)); 27 | void setErrorCallback(void (*callback_function)(errorStruct *)); 28 | void removeMessageCallback(); 29 | void removeErrorCallback(); 30 | bool isConnected(); 31 | 32 | private: 33 | int port; 34 | std::string ip; 35 | unsigned int bytes_for_package_size; 36 | unsigned int size_of_packages; 37 | bool connected; 38 | WSADATA WSAData; 39 | SOCKET socket; 40 | SOCKADDR_IN addr; 41 | HANDLE thread; 42 | bool thread_started; 43 | bool errorWhileReceiving; 44 | bool errorWhileSending; 45 | void (*callback)(messageStruct *); 46 | void (*callbackError)(errorStruct *); 47 | bool errorReceiving(int result); 48 | bool errorSending(int result); 49 | void initSocket(std::string ip, int port); 50 | void initParameters(); 51 | void startThread(); 52 | 53 | static DWORD messageThread(LPVOID param) { 54 | SocketClient *client = (SocketClient*)param; 55 | client->startThread(); 56 | return 0; 57 | } 58 | }; 59 | 60 | struct messageStruct 61 | { 62 | SocketClient client; 63 | std::string message; 64 | messageStruct(SocketClient client, std::string message) : client(client), message(message) {} 65 | }; 66 | 67 | struct errorStruct 68 | { 69 | SocketClient client; 70 | int code; 71 | std::string message; 72 | errorStruct(SocketClient client, int code, std::string message) : client(client), code(code), message(message) {} 73 | }; 74 | 75 | #endif // SOCKETCLIENT_H 76 | -------------------------------------------------------------------------------- /include/SocketServer.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKETSERVER_H 2 | #define SOCKETSERVER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class SocketServer 9 | { 10 | public: 11 | SocketServer(int port); 12 | SOCKET accept(); 13 | void close(); 14 | private: 15 | int port; 16 | WSADATA WSAData; 17 | SOCKET server; 18 | SOCKADDR_IN addr; 19 | }; 20 | 21 | #endif // SOCKETSERVER_H 22 | -------------------------------------------------------------------------------- /library/libSocket.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omaraflak/Asynchronous-Socket-Class-C-Windows/e90d62833a8b8d9812ff4f567318617ba194bfe7/library/libSocket.a -------------------------------------------------------------------------------- /main_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "SocketClient.h" 4 | 5 | using namespace std; 6 | 7 | void onError(errorStruct *e) 8 | { 9 | cout << e->message << endl; 10 | } 11 | 12 | int main() 13 | { 14 | SocketClient client("127.0.0.1", 5555); 15 | client.setErrorCallback(onError); 16 | client.connect(); 17 | 18 | string str; 19 | while(1) 20 | { 21 | cout << ">"; 22 | getline(cin, str); 23 | client.send(str); 24 | } 25 | 26 | /* NEW */ // You can now send streams this way 27 | 28 | ifstream file("/path/to/file"); 29 | client.send(file); // The server will receive the STRING CONTENT of the file. 30 | // But I'm working on a new version to receive the whole file directly (not as a string) 31 | /* NEW */ 32 | 33 | client.close(); 34 | } 35 | -------------------------------------------------------------------------------- /main_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SocketClient.h" 3 | #include "SocketServer.h" 4 | 5 | using namespace std; 6 | 7 | bool good=true; 8 | 9 | void messageReceived(messageStruct *s) 10 | { 11 | cout << "client: " << s->message << endl; 12 | } 13 | 14 | void errorOccurred(errorStruct *e) 15 | { 16 | cout << e->code << " : " << e->message << endl; 17 | good=false; 18 | } 19 | 20 | int main() 21 | { 22 | SocketServer server(5555); 23 | SocketClient client(server.accept()); 24 | client.setErrorCallback(errorOccurred); 25 | client.setMessageCallback(messageReceived); 26 | 27 | while(good){}; 28 | 29 | client.close(); 30 | server.close(); 31 | } 32 | -------------------------------------------------------------------------------- /src/SocketClient.cpp: -------------------------------------------------------------------------------- 1 | #include "SocketClient.h" 2 | 3 | SocketClient::SocketClient(std::string ip, int port) 4 | { 5 | this->ip=ip; 6 | this->port=port; 7 | this->connected=false; 8 | initParameters(); 9 | initSocket(ip, port); 10 | } 11 | 12 | SocketClient::SocketClient(SOCKET socket) 13 | { 14 | this->socket=socket; 15 | this->connected=true; 16 | initParameters(); 17 | } 18 | 19 | SocketClient::SocketClient(){} 20 | 21 | void SocketClient::initSocket(std::string ip, int port) 22 | { 23 | WSAStartup(MAKEWORD(2,0), &WSAData); 24 | this->socket = WINSOCK_API_LINKAGE::socket(AF_INET, SOCK_STREAM, 0); 25 | this->addr.sin_addr.s_addr = inet_addr(ip.c_str()); 26 | this->addr.sin_family = AF_INET; 27 | this->addr.sin_port = htons(port); 28 | } 29 | 30 | void SocketClient::initParameters() 31 | { 32 | this->bytes_for_package_size=16; 33 | this->size_of_packages=2048; 34 | this->callback=NULL; 35 | this->callbackError=NULL; 36 | this->thread_started=false; 37 | this->errorWhileReceiving=false; 38 | this->errorWhileSending=false; 39 | } 40 | 41 | int SocketClient::connect() 42 | { 43 | int r = WINSOCK_API_LINKAGE::connect(socket, (SOCKADDR *)&addr, sizeof(addr)); 44 | if(r==SOCKET_ERROR) 45 | { 46 | if(callbackError!=NULL) 47 | { 48 | errorStruct error(*this, WSAGetLastError(), "Error while connecting."); 49 | callbackError(&error); 50 | } 51 | } 52 | else 53 | connected=true; 54 | 55 | return r; 56 | } 57 | 58 | void SocketClient::close() 59 | { 60 | if(thread_started) 61 | removeMessageCallback(); 62 | removeErrorCallback(); 63 | WINSOCK_API_LINKAGE::closesocket(socket); 64 | WSACleanup(); 65 | } 66 | 67 | void SocketClient::send(std::string message) 68 | { 69 | std::stringstream ss; 70 | ss << message; 71 | send(ss); 72 | } 73 | 74 | void SocketClient::send(std::istream &stream) 75 | { 76 | char buffer[size_of_packages]; 77 | int streamsize, p, result; 78 | std::stringstream ss; 79 | std::string strSize; 80 | 81 | stream.seekg(0, std::ios::end); 82 | streamsize = stream.tellg(); 83 | stream.seekg(std::ios::beg); 84 | 85 | ss << streamsize; 86 | strSize = ss.str(); 87 | 88 | while(strSize.size()> n; 148 | 149 | Sleep(1); 150 | 151 | std::string message; 152 | unsigned int nbLoop = n%size_of_packages==0?n/size_of_packages:n/size_of_packages+1; 153 | for (unsigned int i=0 ; isize_of_packages=n; 187 | } 188 | 189 | void SocketClient::setBytes_for_package_size(unsigned int n) 190 | { 191 | this->bytes_for_package_size=n; 192 | } 193 | 194 | void SocketClient::setMessageCallback(void (*callback_function)(messageStruct *)) 195 | { 196 | callback = callback_function; 197 | thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)messageThread, this, 0, 0); 198 | thread_started=true; 199 | } 200 | 201 | void SocketClient::removeMessageCallback() 202 | { 203 | CloseHandle(thread); 204 | callback = NULL; 205 | thread_started=false; 206 | } 207 | 208 | void SocketClient::setErrorCallback(void (*callback_function)(errorStruct *)) 209 | { 210 | callbackError = callback_function; 211 | } 212 | 213 | void SocketClient::removeErrorCallback() 214 | { 215 | callbackError = NULL; 216 | } 217 | 218 | void SocketClient::startThread() 219 | { 220 | while(1) 221 | { 222 | if(connected) 223 | { 224 | std::string message = this->receive(); 225 | if(errorWhileReceiving) 226 | { 227 | errorWhileReceiving=false; 228 | } 229 | else if(errorWhileSending) 230 | { 231 | errorWhileSending=false; 232 | } 233 | else 234 | { 235 | messageStruct m(*this, message); 236 | callback(&m); 237 | } 238 | } 239 | } 240 | } 241 | 242 | bool SocketClient::isConnected() 243 | { 244 | return connected; 245 | } 246 | -------------------------------------------------------------------------------- /src/SocketServer.cpp: -------------------------------------------------------------------------------- 1 | #include "SocketServer.h" 2 | 3 | SocketServer::SocketServer(int port) 4 | { 5 | this->port=port; 6 | 7 | WSAStartup(MAKEWORD(2,0), &WSAData); 8 | server = socket(AF_INET, SOCK_STREAM, 0); 9 | 10 | addr.sin_addr.s_addr = INADDR_ANY; 11 | addr.sin_family = AF_INET; 12 | addr.sin_port = htons(port); 13 | 14 | bind(server, (SOCKADDR *)&addr, sizeof(addr)); 15 | } 16 | 17 | SOCKET SocketServer::accept() 18 | { 19 | listen(server, 0); 20 | SOCKET client; 21 | SOCKADDR_IN clientAddr; 22 | int clientAddrSize = sizeof(clientAddr); 23 | 24 | if((client = WINSOCK_API_LINKAGE::accept(server, (SOCKADDR *)&clientAddr, &clientAddrSize)) != INVALID_SOCKET) 25 | { 26 | return client; 27 | } 28 | return -1; 29 | } 30 | 31 | void SocketServer::close() 32 | { 33 | WINSOCK_API_LINKAGE::closesocket(server); 34 | } 35 | --------------------------------------------------------------------------------