Client - Server

Started by
19 comments, last by Khatharr 7 years, 4 months ago

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

Advertisement

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

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.

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).

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.

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

i get errors

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

Hello to all my stalkers.

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.

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

Regards the error, read this https://msdn.microsoft.com/en-us/library/ybk95axf.aspx (use sprintf_s instead).

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.

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).

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 <WinSock2.h>
#include <iostream>
#include <Windows.h>

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);
}
}

This topic is closed to new replies.

Advertisement