#30 - SDL_NET TCP Socket Class

Date: 2018-10-13 12:00 - C++

Class to wrap a TCP socket in a class with methods to read and write common data types.

// TCPSocket.h
#ifndef _TCPSOCKET__H_
#define _TCPSOCKET__H_

#include <SDL/SDL_net.h>
#include "NetAddress.h"

#define checkError(f) if((f) <= 0) throw std::string(SDLNet_GetError())

class TCPSocket {
	bool _isServer;
	TCPsocket _socket;
	SDLNet_SocketSet _socketSet;
	friend class Server;
	TCPSocket(TCPsocket socket);
public:
	TCPSocket();
	TCPSocket(NetAddress& addr);
	void connect(NetAddress& addr);
	TCPSocket* accept();
	void close();

	unsigned int avalible();
	// READ
	std::string readString();
	unsigned int readUInt() { unsigned int v; checkError(SDLNet_TCP_Recv(_socket, &v, sizeof(v))); return v; }
	unsigned short readUShort() { unsigned short v; checkError(SDLNet_TCP_Recv(_socket, &v, sizeof(v))); return v; }
	unsigned char readUChar() { unsigned char v; checkError(SDLNet_TCP_Recv(_socket, &v, sizeof(v))); return v; }
	int readInt() { int v; checkError(SDLNet_TCP_Recv(_socket, &v, sizeof(v))); return v; }
	short readShort() { short v; checkError(SDLNet_TCP_Recv(_socket, &v, sizeof(v))); return v; }
	char readChar() { char v; checkError(SDLNet_TCP_Recv(_socket, &v, sizeof(v))); return v; }
	float readFloat() { float v; checkError(SDLNet_TCP_Recv(_socket, &v, sizeof(v))); return v; }
	double readDouble() { double v; checkError(SDLNet_TCP_Recv(_socket, &v, sizeof(v))); return v; }
	int readCustom(void* data, unsigned int length) { int recv = 0; checkError(recv = SDLNet_TCP_Recv(_socket, data, length)); return recv; }
	// WRITE
	void writeString(std::string str) { writeUShort((unsigned short)str.length()); checkError(SDLNet_TCP_Send(_socket, str.c_str(), str.length())); }
	void writeUInt(unsigned int val) { checkError(SDLNet_TCP_Send(_socket, &val, sizeof(val))); }
	void writeUShort(unsigned short val) { checkError(SDLNet_TCP_Send(_socket, &val, sizeof(val))); }
	void writeUChar(unsigned char val) { checkError(SDLNet_TCP_Send(_socket, &val, sizeof(val))); }
	void writeInt(int val) { checkError(SDLNet_TCP_Send(_socket, &val, sizeof(val))); }
	void writeUShort(short val) { checkError(SDLNet_TCP_Send(_socket, &val, sizeof(val))); }
	void writeChar(char val) { checkError(SDLNet_TCP_Send(_socket, &val, sizeof(val))); }
	void writeFloat(float val) { checkError(SDLNet_TCP_Send(_socket, &val, sizeof(val))); }
	void writeDouble(double val) { checkError(SDLNet_TCP_Send(_socket, &val, sizeof(val))); }
	void writeCustom(void* data, unsigned int length) { checkError(SDLNet_TCP_Send(_socket, data, length)); }

	virtual ~TCPSocket();
};

#endif

// TCPSocket.cpp
#include "TCPSocket.h"

TCPSocket::TCPSocket(TCPsocket socket) : _socket(socket), _socketSet(NULL), _isServer(false) {
	_socketSet = SDLNet_AllocSocketSet(1);
}

TCPSocket::TCPSocket() : _socket(NULL), _socketSet(NULL), _isServer(false) {
	_socketSet = SDLNet_AllocSocketSet(1);
}

TCPSocket::TCPSocket(NetAddress& addr) : TCPSocket() {
	connect(addr);
}

void TCPSocket::connect(NetAddress& addr) {
	IPaddress* ipAddr = addr.getAddress();
	_isServer = (ipAddr->host == INADDR_ANY || ipAddr->host == INADDR_NONE);

	if((_socket = SDLNet_TCP_Open(ipAddr)) == NULL)
		throw std::string("TCPSocket error: SDL_Net: " + std::string(SDLNet_GetError()));

	SDLNet_TCP_AddSocket(_socketSet, _socket);
}

TCPSocket* TCPSocket::accept() {
	TCPsocket client = NULL;
	if(!_isServer) {
		throw std::string("TCPSocket error: Not a server! Can't call accept()");
	}

	if (avalible() == 0 || !SDLNet_SocketReady(_socket)) {
		return NULL;
	}

	if((client = SDLNet_TCP_Accept(_socket)) == NULL) {
		SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags::SDL_MESSAGEBOX_INFORMATION, "ERROR", SDLNet_GetError(), NULL);
		return NULL;
	}
	return new TCPSocket(client);
}

void TCPSocket::close() {
	if (_socket != NULL) {
		SDLNet_TCP_DelSocket(_socketSet, _socket);
		SDLNet_TCP_Close(_socket);
		_socket = NULL;
	}
}

unsigned int TCPSocket::avalible() {
	return SDLNet_CheckSockets(_socketSet, -1);
}

std::string TCPSocket::readString() {
	unsigned short size = readUShort();
	char* tmp = new char[size + 1];
	int read = readCustom(tmp, size);
	tmp[read] = 0;
	std::string str(tmp);
	delete[] tmp;
	return str;
}

TCPSocket::~TCPSocket() {
	close();
	if (_socketSet != NULL) {
		SDLNet_FreeSocketSet(_socketSet);
	}
}

Previous snippet | Next snippet