I wrote a socket library in C++, to wrap Winsock. I found it a bit tiring using winsock2 - I'd say it's a bit complex, compared to, for instance, the Python socket library.
My code, header file:
#pragma once
#pragma comment(lib,"WS2_32.lib")
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <windows.h>
#include <string>
#include <iostream>
enum flags{
TCPType = 0,
UDPType = 1
};
inline flags operator|(const flags& x, const flags& y){
return static_cast<flags>(static_cast<int>(x)|static_cast<int>(y));
}
class Socket
{
private:
std::string ip;
std::string port;
SOCKET* currentSocket = nullptr;
bool isTcp;
public:
Socket(flags f = TCPType);
~Socket();
bool Connect(const std::string& address, const std::string& port);
bool BindToPort(int p);
bool Listen();
bool isTcpType();
int ReceiveAll(void* buffer, int size);
int Receive(void* buffer, int size);
int Sendall(void* buffer, int size);
int Send(void* buffer, int size);
std::string getAddress() const;
std::string getPort() const;
Socket* AcceptConnection();
void close();
static bool InitWinsock();
};
And the source file:
#include "pch.h"
#include "Socket.h"
Socket::Socket(flags f)
{
isTcp = !f;
auto connectionType = SOCK_DGRAM;
auto b = 0;
if (isTcp) {
connectionType = SOCK_STREAM;
b = IPPROTO_TCP;
}
SOCKET mainSocket = socket(AF_INET, connectionType, b);
if (mainSocket == INVALID_SOCKET)
{
std::cerr << "Error creating socket: " << WSAGetLastError() << '\n';
WSACleanup();
}
currentSocket = new SOCKET(mainSocket);
}
Socket::~Socket()
{
if(currentSocket != nullptr)
delete currentSocket;
}
bool Socket::Connect(const std::string& address, const std::string& port){
addrinfo hints, *result = nullptr;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int iResult = getaddrinfo(address.c_str(), port.c_str(), &hints, &result);
if (iResult != 0) {
std::cerr << "getaddrinfo failed with error: " << iResult << '\n';
WSACleanup();
return false;
}
addrinfo *ptr = result;
iResult = connect(*currentSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(*currentSocket);
*currentSocket = INVALID_SOCKET;
}
return 0;
}
bool Socket::BindToPort(int p){
if (currentSocket == nullptr)
return false;
sockaddr_in service;
memset(&service, 0, sizeof(service));
service.sin_family = AF_INET;
InetPton(AF_INET, (PCWSTR)("127.0.0.1"), &service.sin_addr.s_addr);
service.sin_port = htons(p);
if(bind(*currentSocket, (SOCKADDR *)& service, sizeof(sockaddr)) == SOCKET_ERROR)
{
std::cerr << "Error during binding socket: " << WSAGetLastError() << '\n';
closesocket(*currentSocket);
return false;
}
this->port = p;
return true;
}
bool Socket::Listen() {
if (currentSocket == nullptr)
return false;
if(listen(*currentSocket, 1) == SOCKET_ERROR)
std::cerr << "Error during trying to listen on socket: " << WSAGetLastError() << '\n';
ip = "127.0.0.1";
return true;
}
bool Socket::isTcpType(){
return isTcp;
}
int Socket::ReceiveAll(void* buffer, int size) {
int bytesLeft = size, current = 0;
while (bytesLeft > 0) {
int bytesRecv = recv(*currentSocket, static_cast<char*>(buffer), size, 0);
if (bytesRecv < 0)
return -1;
bytesLeft -= bytesRecv;
}
return size;
}
int Socket::Receive(void* buffer, int size){
if (currentSocket == nullptr)
return -1;
int bytesRecv = SOCKET_ERROR;
while(bytesRecv == SOCKET_ERROR)
{
bytesRecv = recv(*currentSocket, static_cast<char*>(buffer), size, 0);
if(bytesRecv == WSAECONNRESET)
break;
if (bytesRecv < 0)
return -1;
}
return bytesRecv;
}
int Socket::Sendall(void* buffer, int size) {
if (currentSocket == nullptr)
return -1;
int bytesSent = 0, counter = 0;
while (counter < size) {
bytesSent = send(*currentSocket, static_cast<const char*>(buffer), size, 0);
counter += bytesSent;
}
return size;
}
int Socket::Send(void* buffer, int size){
if (currentSocket == nullptr)
return -1;
int bytesSent, bytesRecv = SOCKET_ERROR;
bytesSent = send(*currentSocket, static_cast<const char*>(buffer), size, 0);
return bytesSent;
}
std::string Socket::getAddress() const{
return ip;
}
std::string Socket::getPort() const{
return port;
}
Socket* Socket::AcceptConnection(){
if (currentSocket == nullptr)
return false;
SOCKET acceptSocket = SOCKET_ERROR;
while (acceptSocket == SOCKET_ERROR)
{
acceptSocket = accept(*currentSocket, NULL, NULL);
}
Socket* result = new Socket(*this);
result->currentSocket = new SOCKET(acceptSocket);
return result;
}
void Socket::close() {
closesocket(*currentSocket);
delete currentSocket;
WSACleanup();
}
bool Socket::InitWinsock() {
WSADATA wsaData;
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != NO_ERROR) {
std::cerr << "Error during initializing WinSock: " << WSAGetLastError() << '\n';
return false;
}
return true;
}