Skip to main content
GameDev.net gamedev.net
🔒 Locked

Client - Server

Started by alextoti99 Nov 30, 2016 at 6:53 PM 19 replies 5.6k views
Original Post
alextoti99
alextoti99

Guys im creating a client - server communication with a simple chat server with local host now.

But when im loging in with the client the server stops working

also the client is like writing black lines all the time.

the code:

Client:


#include <iostream>
#include <Windows.h>
#include <WinSock.h>

#pragma comment (lib, "ws2_32")

using namespace std;

SOCKET sConnect;
SOCKADDR_IN addr;

int Startup_WinSock()
{
    WSADATA wsaData;
        WORD DllVersion = MAKEWORD(2, 1);
        int Val = WSAStartup(DllVersion, &wsaData);
    return Val;
}

int ClientThread()
{
    char *Buffer = new char[256];
    int size = 0;
    while (true)
    {
        ZeroMemory(Buffer, 256);
        if ((size = recv(sConnect, Buffer, 256, NULL)) > 0);
        {
            cout << Buffer << endl;
        }
        Sleep(50);
    }
}
    int main()
    {
        system("color 0a");

        int Val = Startup_WinSock();

        if (Val != 0)
        {
            cout << "Cant start WinSock" << endl;
            exit(1);
        }
        sConnect = socket(AF_INET, SOCK_STREAM, NULL);
        addr.sin_addr.s_addr = inet_addr("127.0.0.1");
        addr.sin_port = htons(2222);
        addr.sin_family = AF_INET;
        cout << "Please press [ENTER]" << endl;
        cin.get();
        Val = connect(sConnect, (SOCKADDR*)&addr, sizeof(addr));

        if (Val != 0)
        {
            cout << "Cant login to the server" << endl;
            main();
        }
        else
        {
            system("cls");
            int ID;
            char *nID = new char[64];
            char *hello = new char[256];
            ZeroMemory(hello, 256);
            ZeroMemory(nID, 64);
            recv(sConnect, nID, 64, NULL);
            recv(sConnect, hello, 64, NULL);
            ID = atoi(nID);
            cout << hello << endl;
            cout << "Your ID:" << " " << ID << endl;
            cout << " If you are ready press [ENTER]" << endl;
            cin.get();

            system("cls");
            CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientThread, NULL, NULL, NULL);

            while (true)
            {
                char *MSG = new char[256];
                ZeroMemory(MSG, 256);
                cin.getline(MSG, 256);
                send(sConnect, MSG, 256, NULL);
                Sleep(50);
            }
        }
        return 0;
    }

Server:


#include <iostream>
#include <Windows.h>
#include <WinSock.h>

using namespace std;

#pragma comment (lib, "ws2_32")

SOCKADDR_IN addr; // this  saves the ip and port of the server
int addrlen = sizeof(addr);

int Counter; // this counts how many clients are connected in the server

SOCKET sConnect; // 1 socket for incoming connections
SOCKET sListen; // 1 socket for listening
SOCKET *Connections; // 1 which saves the connections

int InitWinSock()
{
	int Val = 0; 
	WSAData wsaData;
	WORD DllVersion = MAKEWORD(2, 1);

	Val = WSAStartup(DllVersion, &wsaData);



	return Val;
}

int ServerThread(int ID)
{
	char *Buffer = new char[256];
	int size = 0;
	while (true)
	{
		ZeroMemory(Buffer, 256);
		for (int a = 0; a < Counter; a++)
		{
		if ((size = recv(Connections[ID], Buffer, 256, NULL)) > 0)
			
				{if (Connections[a] == Connections[ID])
					ZeroMemory(Buffer, 256);
				printf(Buffer, "Client[%i]: %s", ID, Buffer);
				cout << "New Message: " << Buffer << endl;
				}
		else {
			ZeroMemory(Buffer, 256);
			printf(Buffer,  "Client[%i]: %s", ID, Buffer);
			send(Connections[a], Buffer, 256, NULL);
		}
			}
	}
}

int main ()
{
	system("color 0a");

	cout << "Server Started Successfully" << endl;

	int Val = InitWinSock();

	if (Val != 0)
	{
		MessageBoxA(NULL, "Error while attempting to load WinSock", "Error", MB_OK | MB_ICONERROR);
		exit(1);
	}

	Connections = (SOCKET*)calloc(64, sizeof(SOCKET));

	sListen = socket(AF_INET, SOCK_STREAM, NULL);
	sConnect = socket(AF_INET, SOCK_STREAM, NULL);

	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	addr.sin_port = htons(2222);
	addr.sin_family = AF_INET;

	bind(sListen, (SOCKADDR*)&addr, sizeof(addr));
	listen(sListen, 64);

	while (true)
	{
		if (sConnect = accept(sListen, (SOCKADDR*)&addr, &addrlen))
		{
			Connections[Counter] = sConnect;
			char *Name = new char[64];
			ZeroMemory(Name, 64);
			printf(Name, "%i", Counter);
			send(Connections[Counter], Name, 64, NULL);
			send(Connections[Counter], "Welcome To The Mysteries Of Genesys", 64, NULL);
			cout << "New Connection" << endl;
			Counter++;
			CreateThread(NULL, NULL, NULL,(LPTHREAD_START_ROUTINE)ServerThread, NULL, NULL);
		}
		Sleep(50);
	}
}

Could u help me? :3

Thx in advance

But if i use the one created some hours before:


#include <WinSock.h>
#include <iostream>
#include <Windows.h>

using namespace std;

#pragma comment (lib, "ws2_32.lib") //<-- we need this lib

SOCKADDR_IN addr; // this  saves the ip and port of the server
int addrlen = sizeof(addr);

int Counter; // this counts how many clients are connected in the server

SOCKET sConnect; // 1 socket for incoming connections
SOCKET sListen; // 1 socket for listening
SOCKET *Connections; // 1 which saves the connections

int InitWinSock()
{
	int Val = 0; // this will say to us when the action will fail
	WSAData wsaData;
	WORD DllVersion = MAKEWORD(2, 1);

	Val = WSAStartup(DllVersion, &wsaData); //here the winsock will be initialized



	return Val;
}

int ServerThread(int ID)
{
	char *Buffer = new char[256];
	int size = 0;

	while (true)
	{
		ZeroMemory(Buffer, 256);

		if ((size = recv(Connections[ID], Buffer, 256, NULL)) > 0);  // the following steps will be followed only if the msg isnt empty
		{
			for (int a = 0; a < Counter; a++)
			{
				if (Connections[a] == Connections[ID])
				{
					ZeroMemory(Buffer, 256);
					printf(Buffer, " Client[%i]: %s", ID, Buffer);
					cout << Buffer << endl;
				}
				else
				{
					ZeroMemory(Buffer, 256);
					printf(Buffer, " Client[%i]: %s", ID, Buffer);
					send(Connections[a], Buffer, 256, NULL);
				}
			}
		}
	}
}
	int main()
	{
		cout << "Server started" << endl;
		system("Color  0a");

		int  Val = InitWinSock();

		if (Val != 0)
		{
			MessageBoxA(NULL, " Error while attempting to Startup Winsock!", "Error", MB_OK | MB_ICONERROR);
			exit(1);
		}

		Connections = (SOCKET*)calloc(64, sizeof(SOCKET));
		sListen = socket(AF_INET, SOCK_STREAM, NULL);
		sConnect = socket(AF_INET, SOCK_STREAM, NULL);

		addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // server ip
		addr.sin_port = htons(2222); // server port
		addr.sin_family = AF_INET; // this is the kind of connection

		bind(sListen, (SOCKADDR*)&addr, sizeof(addr)); // first we bind the server to the ip and port

		listen(sListen, 64);

		while (true) // in this endless loop we search for connections
		{
			if (sConnect = accept(sListen, (SOCKADDR*)&addr, &addrlen)) // here the connection is accepted
			{
				Connections[Counter] = sConnect;

				char *Name = new char[64]; // the name of the client

				ZeroMemory(Name, 64); // we make  the char empty

				printf(Name, "%i", Counter);

				send(Connections[Counter], Name, 64, NULL);
				send(Connections[Counter], "Welcome", 64, NULL); // welcome msg

				cout << "New Connection" << Counter << endl;

				Counter++; // +1 client :D		

				CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ServerThread, (LPVOID)(Counter - 1), NULL, NULL);

			}
			Sleep(50); // the server waits for 50 miliseconds
		}
	}

is responding well, but the messages from the clients arent sent to the others also the client is like writing black lines all the time again

alextoti99
alextoti99

also i always get the same id (0) from every client

edit:

changed the client code to:


#include <iostream>
#include <Windows.h>
#include <WinSock.h>

#pragma comment (lib, "ws2_32")

using namespace std;

SOCKET sConnect;
SOCKADDR_IN addr;

int Startup_WinSock()
{
	WSADATA wsaData;
		WORD DllVersion = MAKEWORD(2, 1);
		int Val = WSAStartup(DllVersion, &wsaData);
	return Val;
}

int ClientThread()
{
	char *Buffer = new char[256];
	int size = 0;

	while (true)
	{
		ZeroMemory(Buffer, 256);

		if ((size = recv(sConnect, Buffer, 256, NULL)) > 0);
		{
			cout << Buffer << endl;
		}
		Sleep(50);
	}

}

	int main()
	{
		system("color 0a");

		int Val = Startup_WinSock();

		if (Val != 0)
		{
			cout << "Cant start WinSock" << endl;
			exit(1);
		}
		sConnect = socket(AF_INET, SOCK_STREAM, NULL);
		addr.sin_addr.s_addr = inet_addr("127.0.0.1");
		addr.sin_port = htons(2222);
		addr.sin_family = AF_INET;
		cout << "Please press [ENTER]" << endl;
		cin.get();
		Val = connect(sConnect, (SOCKADDR*)&addr, sizeof(addr));

		if (Val != 0)
		{
			cout << "Cant login to the server" << endl;
			main();
		}
		else
		{
			system("cls");
			int ID;
			char *nID = new char[64];
			char *hello = new char[256];
			ZeroMemory(hello, 256);
			ZeroMemory(nID, 64);
			recv(sConnect, nID, 64, NULL);
			recv(sConnect, hello, 64, NULL);
			ID = atoi(nID);
			cout << hello << endl;
			cout << "Your ID:" << " " << ID << endl;
			cout << " If you are ready press [ENTER]" << endl;
			cin.get();

			system("cls");
			CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientThread, NULL, NULL, NULL);

			while (true)
			{
				char *MSG = new char[256];

				ZeroMemory(MSG, 256);

				cin.getline(MSG, 256);

				send(sConnect, MSG, 256, NULL);

				Sleep(50);
			}
		}
		return 0;
	}

and when im sending a msg from the other client its like a get a msg but writing nth its a blank like to the other client

KnolanCross
KnolanCross

Some bad smells I found looking at your code (I am a linux programer, so take what I say with a grain of salt).

First, why are you creating one thread for each socket? You can use select or poll to watch for multiple sockets, it will lead to a much simpler code.

Second, on the server code, are those printfs correct? Is there any redefinition of it for windows that I am not aware about? Because I am pretty sure you should be using sprintf there instead (or even better, snprintf).

Finally, some of your "send" commands are with constant 64 size, when the buffers are not 64 bytes long, you should definitely fix this.

Khatharr
Khatharr

Not pimping this, really, because it's not completed yet and some of it is still very messy, but please take a look at the TCPServer and TCPSocket classes and make note of some of the differences:

https://github.com/khatharr/SimpleSocks

You may also want to look at the implementation of the SSocks::select() function to see how ::select() is used, since - as KnolanCross mentioned - a unique thread of each connection is often overkill.

Actually, to simplify some of it a bit...


Using recv()

std::vector<char> SSocks::TCPSocket::coreRecv(size_t len) {
  if(!isOpen()) { throw std::runtime_error("Attempted recv on closed TCPSocket."); }

  std::vector<char> data(len);
  
  int got = ::recv(sock, data.data(), data.size(), 0);
  if(got == SOCKET_ERROR) { 
    close();
    throw std::runtime_error("Error reading from socket!");
  }

  //recv() returns zero if the socket was closed by the remote host
  if(got == 0) { close(); }

  data.resize(got);

  return data;
}

.


Using send()

size_t SSocks::TCPSocket::send(const char* data, size_t len) {
  if(!isOpen()) { throw std::runtime_error("Attempted send on closed TCPSocket."); }

  int sent = ::send(sock, data, len, 0);
  if(sent == SOCKET_ERROR) {
    close(); //if a socket operation fails you should usually assume that the socket is now bad
    throw std::runtime_error("Failure during send.");
  }

  return sent;
}

.


Setting up a listener

//localHostAddr should be the IP address of a local interface, not a host name. the default is "0.0.0.0" to listen on all interfaces
void SSocks::TCPServer::start(uint16_t port, const std::string& localHostAddr) {

  //We need a sockaddr_in to bind the server to a port and interface.
  sockaddr_in sain = {0};
  sain.sin_family = AF_INET;
  sain.sin_port = htons(port);

  //This shouldn't fail unless you type in gibberish, but let's be safe.
  int result = inet_pton(AF_INET, localHostAddr.c_str(), &sain.sin_addr);
  switch(result) {
  case 0: throw std::runtime_error("Attempted to start server on interface with invalid address string.");
  case -1: throw std::runtime_error("Failed to generate address from string while creating server.");
  }

  //assume a member variable named 'servSock' that holds the socket handle for the listener
  servSock = ::socket(AF_INET, SOCK_STREAM, 0);
  //~~check for errors here
  
  //bind the socket
  result = bind(servSock, reinterpret_cast<sockaddr*>(&sain), sizeof(sain));
  if(result) { throw std::runtime_error("Failed to bind listener."); }

  result = listen(servSock, SOMAXCONN);
  if(result) { throw std::runtime_error("Failed to listen on bound socket."); }
}

.


Accepting an incoming connection

int SSocks::TCPServer::accept() {
  if(!isOpen()) { throw std::runtime_error("Attemtped to wait for connections on closed TCPServer."); }

  int nuSock = ::accept(servSock, nullptr, nullptr);
  if(nuSock == SOCKET_ERROR) { throw std::runtime_error("Failure while accepting incoming connection."); }

  return nuSock;
}

.


Connecting to a remote host

void SSocks::TCPSocket::connect(const HostAddress& host) {
  if(isOpen()) { close(); }

  //assume this is a member variable
  sock = ::socket(SOCK_STREAM, IPPROTO_TCP, 0);
  //~~ check for errors

  //try to connect to address
  int err = ::connect(sock, host, sizeof(sockaddr_in));
  if(err) {
    closesocket(sock);
    throw std::runtime_error("Failed to connect to remote host.");
  }
}

.

Keep in mind that if you want to print strings that you got over the wire you may need to manually place a null terminator at the end of the string to indicate its end.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
alextoti99
alextoti99

if i use sprintfs i get errors , that says that they are not safe

Lactose
Lactose



i get errors

When asking about errors, please provide them exactly. Copy & paste them, with error codes.

Hello to all my stalkers.
Kylotan
Kylotan



if i use sprintfs i get errors , that says that they are not safe

Your entire code is unsafe given that you're firing off threads that share sockets and data with no attempt at synchronisation or locks. You really need to reconsider your entire approach.

KnolanCross
KnolanCross
if i use sprintfs i get errors , that says that they are not safe

The short answer is: use snprintf (notice the 'n' threre).

Where you have:


printf(Name, "%i", Counter);

Change to:


snprintf(Name, 64, "%i", Counter);

The long answer is:

printf is used to write on the stdout, and on stdout only. The reason you are not having any error messages is because it will receive a formated string and any number of arguments. When you use:


printf(Name, "%i", Counter);

The compiler will assume that Name is a formatted string such as "Hello %i", and the following arguments will be used to format the percent marked points in your string, since the compiler doesn't know the contents of the variable Name it will assume that you know what you are doing and leave no warnings or errors. When your code is executed, Name is empty and it will print an empty string and ignore the "%i" and Counter variables.

The compiler is complaining about sprintf because it is indeed unsafe. If you try to write 80 bytes on the Name variable, it will not check the actual size and it will write outside it bounds, which will likely end up crashing your program sooner or later (in my experience, later, on another malloc).

On the other hand, snprintf will use the second argument as the size of the buffer and will not write more than n bytes (or n -1, depends on the implementation) on it, hence it is considered safe.

Here is the documentation for snprintf: https://msdn.microsoft.com/en-us/library/2ts7cx93.aspx

PS: you should free the Name variable after you send it, or use char Name[64] instead.

alextoti99
alextoti99

well i changed the code but now im taking this error:

Severity Code Description Project File Line Suppression State
Error C4996 'inet_addr': Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings client c:\users\alex_\documents\visual studio 2015\projects\client\client\main.cpp 20

the code:

#pragma comment(lib,"ws2_32.lib")
#include
#include
#include

int main()
{
system("color 0a");
//Winsock Startup
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
{
MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
exit(1);
}

SOCKADDR_IN addr; //Address to be binded to our Connection socket
int sizeofaddr = sizeof(addr); //Need sizeofaddr for the connect function
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // The ip that the client will be logged in
addr.sin_port = htons(555); // The port that will use
addr.sin_family = AF_INET; //IPv4 Socket

SOCKET Connection = socket(AF_INET, SOCK_STREAM, NULL); //Set Connection socket
if (connect(Connection, (SOCKADDR*)&addr, sizeofaddr) != 0) //If we are unable to connect...
{
MessageBoxA(NULL, "Failed to Connect", "Error", MB_OK | MB_ICONERROR);
return 0; //Failed to Connect
}
std::cout << "Connected!" << std::endl;

char MOTD[256];
recv(Connection, MOTD, sizeof(MOTD), NULL); // The msg that the client will get on login
std::cout << "MOTD:" << MOTD << std::endl;
while (true)
{
Sleep(10);
}
}

Kylotan
Kylotan

Did you try doing what the error message tells you to?

alextoti99
alextoti99

if i use inet_pton i get this error:

Severity Code Description Project File Line Suppression State
Error (active) identifier "inet_pton" is undefined server c:\Users\alex_\Documents\Visual Studio 2015\Projects\server\server\main.cpp 37
Severity Code Description Project File Line Suppression State
Error (active) identifier "InetPton" is undefined server c:\Users\alex_\Documents\Visual Studio 2015\Projects\server\server\main.cpp 37


but if i add this
#include

addr.sin_addr.s_addr = inet_pton("127.0.0.1"); //Broadcast locally

but im getting this error

Severity Code Description Project File Line Suppression State
Error (active) argument of type "const char *" is incompatible with parameter of type "INT" server c:\Users\alex_\Documents\Visual Studio 2015\Projects\server\server\main.cpp 38

Lactose
Lactose



fixed it

How? If others find this thread later, they might have the same issue :)

Hello to all my stalkers.
alextoti99
alextoti99

on top after or before the #include

add this

#define _WINSOCK_DEPRECATED_NO_WARNINGS?

if u have error with this

add this

#pragma warning(disable : 4996)?

alextoti99
alextoti99

hi again:

main.cpp:


#include "Server.h"
#include <iostream>
#include "ConfigFile.cpp"

using namespace std;

int main()
{
	system("color 0a");
	std::cout << "Server Started" << std::endl;
	Server MyServer(srvport); //port is stored in the config file
	for (int i = 0; i < 100; i++) //Up to 100 times...
	{
		MyServer.ListenForNewConnection(); //Accept new connection (if someones trying to connect)
	}
	system("pause");
	return 0;
}

ConfigFile.cpp:


#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <fstream>

class Convert
{
public:
	template <typename T>
	static std::string T_to_string(T const &val)
	{
		std::ostringstream ostr;
		ostr << val;

		return ostr.str();
	}

	template <typename T>
	static T string_to_T(std::string const &val)
	{
		std::istringstream istr(val);
		T returnVal;
		if (!(istr >> returnVal))
			exitWithError("CFG: Not a valid " + (std::string)typeid(T).name() + " received!\n");

		return returnVal;
	}

	template <>
	static std::string string_to_T(std::string const &val)
	{
		return val;
	}
};

void exitWithError(const std::string &error)
{
	std::cout << error;
	std::cin.ignore();
	std::cin.get();

	exit(EXIT_FAILURE);
}

class ConfigFile
{
private:
	std::map<std::string, std::string> contents;
	std::string fName;

	void removeComment(std::string &line) const
	{
		if (line.find(';') != line.npos)
			line.erase(line.find(';'));
	}

	bool onlyWhitespace(const std::string &line) const
	{
		return (line.find_first_not_of(' ') == line.npos);
	}
	bool validLine(const std::string &line) const
	{
		std::string temp = line;
		temp.erase(0, temp.find_first_not_of("\t "));
		if (temp[0] == '=')
			return false;

		for (size_t i = temp.find('=') + 1; i < temp.length(); i++)
			if (temp[i] != ' ')
				return true;

		return false;
	}

	void extractKey(std::string &key, size_t const &sepPos, const std::string &line) const
	{
		key = line.substr(0, sepPos);
		if (key.find('\t') != line.npos || key.find(' ') != line.npos)
			key.erase(key.find_first_of("\t "));
	}
	void extractValue(std::string &value, size_t const &sepPos, const std::string &line) const
	{
		value = line.substr(sepPos + 1);
		value.erase(0, value.find_first_not_of("\t "));
		value.erase(value.find_last_not_of("\t ") + 1);
	}

	void extractContents(const std::string &line)
	{
		std::string temp = line;
		temp.erase(0, temp.find_first_not_of("\t "));
		size_t sepPos = temp.find('=');

		std::string key, value;
		extractKey(key, sepPos, temp);
		extractValue(value, sepPos, temp);

		if (!keyExists(key))
			contents.insert(std::pair<std::string, std::string>(key, value));
		else
			exitWithError("CFG: Can only have unique key names!\n");
	}

	void parseLine(const std::string &line, size_t const lineNo)
	{
		if (line.find('=') == line.npos)
			exitWithError("CFG: Couldn't find separator on line: " + Convert::T_to_string(lineNo) + "\n");

		if (!validLine(line))
			exitWithError("CFG: Bad format for line: " + Convert::T_to_string(lineNo) + "\n");

		extractContents(line);
	}

	void ExtractKeys()
	{
		std::ifstream file;
		file.open(fName.c_str());
		if (!file)
			exitWithError("CFG: File " + fName + " couldn't be found!\n");

		std::string line;
		size_t lineNo = 0;
		while (std::getline(file, line))
		{
			lineNo++;
			std::string temp = line;

			if (temp.empty())
				continue;

			removeComment(temp);
			if (onlyWhitespace(temp))
				continue;

			parseLine(temp, lineNo);
		}

		file.close();
	}
public:
	ConfigFile(const std::string &fName)
	{
		this->fName = fName;
		ExtractKeys();
	}

	bool keyExists(const std::string &key) const
	{
		return contents.find(key) != contents.end();
	}

	template <typename ValueType>
	ValueType getValueOfKey(const std::string &key, ValueType const &defaultValue = ValueType()) const
	{
		if (!keyExists(key))
			return defaultValue;

		return Convert::string_to_T<ValueType>(contents.find(key)->second);
	}
	};

	int srvport;

int Configs()
{
	ConfigFile cfg("config.cfg");

	int srvport = cfg.getValueOfKey<int>("srvport", 1111);

	std::cin.get();
	return 0;
}

im getting these errors:


Severity	Code	Description	Project	File	Line	Suppression State
Error	LNK2005	"void __cdecl exitWithError(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?exitWithError@@YAXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) already defined in ConfigFile.obj	serverside	C:\Users\alex_\Documents\Visual Studio 2015\Projects\serverside\serverside\Server.obj	1	


Severity	Code	Description	Project	File	Line	Suppression State
Error	LNK2005	"void __cdecl exitWithError(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?exitWithError@@YAXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) already defined in ConfigFile.obj	serverside	C:\Users\alex_\Documents\Visual Studio 2015\Projects\serverside\serverside\Source.obj	1	

Severity	Code	Description	Project	File	Line	Suppression State
Error	LNK1169	one or more multiply defined symbols found	serverside	C:\Users\alex_\Documents\Visual Studio 2015\Projects\serverside\Debug\serverside.exe	1	

Severity	Code	Description	Project	File	Line	Suppression State
Error	LNK2005	_main already defined in Server.obj	serverside	C:\Users\alex_\Documents\Visual Studio 2015\Projects\serverside\serverside\Source.obj	1	

does anyone know how to fix them?

also are the configuration file ok?

and config.cfg:


srvport = 1111;
Khatharr
Khatharr

Define exitWithError() in one place and refer to it. Don't just redefine it in every TLU unless you have some reason to do so.

If you do have such a reason (You really, truly don't, believe me.) then make it static in all the places where it's defined, or put it within the scope of an anonymous namespace.


It also appears to be complaining that you have main() defined more than once...

Wait, are you including .cpp files?

main.cpp:


#include "ConfigFile.cpp"

Nononononononono...

Include headers. Don't include cpp files.

Headers should only contain declarations and inlines, cpp files should contain definitions.

Declaration:


void foo();

Definition:


void foo() {
  std::cout << bar();
}

When you compile your program each cpp file is treated as a translation unit. The compiler pulls in the headers that it includes and builds that unit, then when the units are all compiled the linker starts pasting them together. The reason headers are used is that the cpp file can refer to things that have been declared but not defined - as long as the linker can find those things later on when it's pulling everything together. In your case you're including a cpp file, so the compiler builds 'ConfigFile.cpp' and then tried to build main.cpp, but because of the include there it compiles all of ConfigFile.cpp again in the main.cpp TLU (main.obj). When the linker goes to pull the program together it finds things that exist in both places and it doesn't know which one to use in what place, so you get link errors.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
alextoti99
alextoti99

sth like this?

ConfigFile.cpp:


#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <fstream>

using namespace std;

class Convert
{
public:
    template <typename T>
    static std::string T_to_string(T const &val)
    {
        std::ostringstream ostr;
        ostr << val;

        return ostr.str();
    }

    template <typename T>
    static T string_to_T(std::string const &val)
    {
        std::istringstream istr(val);
        T returnVal;
        if (!(istr >> returnVal))
            cout << "error" << endl;

        return returnVal;
    }

    template <>
    static std::string string_to_T(std::string const &val)
    {
        return val;
    }
};

class ConfigFile
{
private:
    std::map<std::string, std::string> contents;
    std::string fName;

    void removeComment(std::string &line) const
    {
        if (line.find(';') != line.npos)
            line.erase(line.find(';'));
    }

    bool onlyWhitespace(const std::string &line) const
    {
        return (line.find_first_not_of(' ') == line.npos);
    }
    bool validLine(const std::string &line) const
    {
        std::string temp = line;
        temp.erase(0, temp.find_first_not_of("\t "));
        if (temp[0] == '=')
            return false;

        for (size_t i = temp.find('=') + 1; i < temp.length(); i++)
            if (temp[i] != ' ')
                return true;

        return false;
    }

    void extractKey(std::string &key, size_t const &sepPos, const std::string &line) const
    {
        key = line.substr(0, sepPos);
        if (key.find('\t') != line.npos || key.find(' ') != line.npos)
            key.erase(key.find_first_of("\t "));
    }
    void extractValue(std::string &value, size_t const &sepPos, const std::string &line) const
    {
        value = line.substr(sepPos + 1);
        value.erase(0, value.find_first_not_of("\t "));
        value.erase(value.find_last_not_of("\t ") + 1);
    }

    void extractContents(const std::string &line)
    {
        std::string temp = line;
        temp.erase(0, temp.find_first_not_of("\t "));
        size_t sepPos = temp.find('=');

        std::string key, value;
        extractKey(key, sepPos, temp);
        extractValue(value, sepPos, temp);

        if (!keyExists(key))
            contents.insert(std::pair<std::string, std::string>(key, value));
        else
            cout << "error" << endl;
    }

    void parseLine(const std::string &line, size_t const lineNo)
    {
        if (line.find('=') == line.npos)
            cout << "error" << endl;

        if (!validLine(line))
            cout << "bad format" << endl;

        extractContents(line);
    }

    void ExtractKeys()
    {
        std::ifstream file;
        file.open(fName.c_str());
        if (!file)
            cout << "CFG file couldnt be found" << endl;

        std::string line;
        size_t lineNo = 0;
        while (std::getline(file, line))
        {
            lineNo++;
            std::string temp = line;

            if (temp.empty())
                continue;

            removeComment(temp);
            if (onlyWhitespace(temp))
                continue;

            parseLine(temp, lineNo);
        }

        file.close();
    }
public:
    ConfigFile(const std::string &fName)
    {
        this->fName = fName;
        ExtractKeys();
    }

    bool keyExists(const std::string &key) const
    {
        return contents.find(key) != contents.end();
    }

    template <typename ValueType>
    ValueType getValueOfKey(const std::string &key, ValueType const &defaultValue = ValueType()) const
    {
        if (!keyExists(key))
            return defaultValue;

        return Convert::string_to_T<ValueType>(contents.find(key)->second);
    }
};

int mainC()
{
    ConfigFile cfg("config.cfg");
    int srvport = cfg.getValueOfKey<int>("srvport", 1111);
    std::cin.get();
    return 0;
}

Config.h:


#pragma once
#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <fstream>


class Convert;
class ConfigFile;
int mainC();

but im getting errors in the main.cpp


#include "Server.h"
#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <fstream>
#include "ConfigFile.h"

using namespace std;



int main()
{
    system("color 0a");
    std::cout << "Server Started" << std::endl;
    Server MyServer(srvport); //port is stored in the config file
    for (int i = 0; i < 100; i++) //Up to 100 times...
    {
        MyServer.ListenForNewConnection(); //Accept new connection (if someones trying to connect)
    }
    system("pause");
    return 0;
}

Errors:


Severity    Code    Description    Project    File    Line    Suppression State
Error    C2065    'srvport': undeclared identifier    serverside    c:\users\alex_\documents\visual studio 2015\projects\serverside\serverside\source.cpp    17    

Severity    Code    Description    Project    File    Line    Suppression State
Error (active)        identifier "srvport" is undefined    serverside    c:\Users\alex_\Documents\Visual Studio 2015\Projects\serverside\serverside\Source.cpp    17    


(Updated)

Satharis
Satharis
int main()
{
    system("color 0a");
    std::cout << "Server Started" << std::endl;
    Server MyServer(srvport); //port is stored in the config file
    for (int i = 0; i < 100; i++) //Up to 100 times...
    {
        MyServer.ListenForNewConnection(); //Accept new connection (if someones trying to connect)
    }
    system("pause");
    return 0;
}
The error says exactly what your problem is, srvport isn't defined where you're writing it.

Also you can't really put a blank class definition in a header and then a defined one in a cpp file because then the compiler can't figure out the size of the class if anything else tries to instantiate a copy of it.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.