Click here to Skip to main content
15,897,891 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Hi
SOLVED: See end of question

I've written a simple server in C++ which simply listens for connections, assigns a ClientConnection class to each connection, and those sockets receive messages. When my separate client app connects to the server, the connection is acknowledged but the server believes it's receiving a message. Data is sent from my client in a format where the first byte is the data length, (even though no data has been sent at this point) and the server interprets the first byte of what it's receiving to be '-52'.

Hopefully you can see what I've done wrong; it was working fine when I had the threading code in Server.cpp but I moved it to ClientConnection.cpp.

Server.h
#pragma once

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <winsock.h>
#include <vector>
#include <sstream>
#include "..\..\CPPUtils\CPPUtils\DebugUtils.h"
#include "ClientConnection.h"

class __declspec(dllexport) Server
{
public:
	Server();
	~Server();
	//std::vector<ClientConnection*> clients;

private:
	bool listening = false;
	int port = 1123;

};


Server.cpp
#include "stdafx.h"
#include "Server.h"

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

Server::Server()
{
	WSADATA wsaData;
	sockaddr_in server;
	SOCKET listenSocket;

	// start highest version of winsock
	if (WSAStartup(0x101, &wsaData) != 0) return;

	// fill winsock struct
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = INADDR_ANY;
	server.sin_port = htons(port);

	// create listen socket
	listenSocket = socket(AF_INET, SOCK_STREAM, 0);

	if (listenSocket == INVALID_SOCKET) return;

	// bind socket to port
	if (bind(listenSocket, (sockaddr*)&server, sizeof(server)) != 0) return;

	// listen for a connection  
	if (listen(listenSocket, 5) != 0) return;

	SOCKET clientSocket;
	sockaddr_in from;
	int fromlen = sizeof(from);

	while (true)
	{
		// accept connections
		clientSocket = accept(listenSocket, (struct sockaddr*)&from, &fromlen);
		
		//char ip_holder[16];
		//sprintf_s(ip_holder, "%s", ((struct sockaddr_in*)&from)->sin_addr);
		//DebugUtils::msgbox("Server", "Client Connected from IP: ", ip_holder);
		DebugUtils::msgbox("Server", "Client Connected", "");

		// create new thread and pass socket
		ClientConnection* newConn = new ClientConnection((LPVOID)socket);
		//clients.push_back(newConn);
		//delete newConn;
	}

	// shutdown winsock
	closesocket(listenSocket);
	WSACleanup();
}

Server::~Server()
{
	DebugUtils::msgbox("Debug", "Server dtor", "");

	/*for (ClientConnection* conn : clients)
	{
		conn->disconnect();
		delete conn;
	}*/
}


ClientConnection.h
#pragma once

#include <vector>
#include <winsock.h>
#include "..\..\CPPUtils\CPPUtils\ConversionUtils.h"
#include "..\..\CPPUtils\CPPUtils\DebugUtils.h"

#include <string>

class __declspec(dllexport) ClientConnection
{
public:
	ClientConnection(LPVOID socket);
	~ClientConnection();

	void disconnect();

private:
	static DWORD WINAPI StartListenThread(void* str);
	void ListenThread(LPVOID socket);

	bool listening = false;

};


ClientConnection.cpp
#include "stdafx.h"
#include "ClientConnection.h"

struct InstanceSocketStruct
{
	ClientConnection* instance;
	LPVOID socket;

	InstanceSocketStruct(ClientConnection* instance, LPVOID socket)
	{
		this->instance = instance;
		this->socket = socket;
	}
};

ClientConnection::ClientConnection(LPVOID socket)
{
	CreateThread(NULL, 0, StartListenThread, new InstanceSocketStruct(this, socket), 0, NULL);
}

ClientConnection::~ClientConnection()
{
	DebugUtils::msgbox("Debug", "ClientConnection dtor", "");
}

DWORD WINAPI ClientConnection::StartListenThread(void* str)
{
	InstanceSocketStruct* i_str = (InstanceSocketStruct*)str;
	i_str->instance->ListenThread(i_str->socket);

	return 0;
}

void ClientConnection::ListenThread(LPVOID socket)
{
	SOCKET clientSocket = (SOCKET)socket;

	listening = true;

	// listen for data
	while (listening)
	{
		int error;
		
		char length_byte[1];
		error = recv(clientSocket, length_byte, 1, 0); // read length byte
		Sleep(10);
		
		if (error == 0)
		{
			DebugUtils::msgbox("Debug", "Error is 0, closing socket and ending thread", "");
			closesocket(clientSocket);
			ExitThread(0);
		}
		
		char packetID_byte[1];
		recv(clientSocket, packetID_byte, 1, 0); // read packetID byte
		Sleep(10);
		
		int data_length = length_byte[0];
		int packetID = packetID_byte[0];
		DebugUtils::msgbox("Debug", "5:", std::to_string(data_length));
		std::vector<char> data_bytes(data_length);
		recv(clientSocket, data_bytes.data(), data_length, 0); // read data
		Sleep(10);
		DebugUtils::msgbox("Debug", "6", "");
		std::string data = std::string(data_bytes.begin(), data_bytes.end());
		DebugUtils::msgbox("Debug", "Received data: ", data.c_str());
		DebugUtils::msgbox("Debug", "7", "");
		
	}

	DebugUtils::msgbox("Debug", "Exiting thread", "");
	closesocket(clientSocket);
	ExitThread(0);
}

void ClientConnection::disconnect()
{
	DebugUtils::msgbox("Debug", "disconnect", "");
	// send message to client
	listening = false;
}


SOLVED:

I did a derp. Unfortunately the compiler allowed me to make a mistake so I didn't see it.

The solution was to change:
ClientConnection* newConn = new ClientConnection((LPVOID)socket);

to
ClientConnection* newConn = new ClientConnection((LPVOID)clientSocket);


The compiler allowed me to type "socket" as that is indeed the name of a function, but not the socket I was trying to pass.

What I have tried:

Comparing my code to the original, everything seems the same

Inserting several debug points, narrowed the issue down to be that the server believes it's receiving data from somewhere.
Posted
Updated 7-Dec-17 10:25am
v5
Comments
jeron1 7-Dec-17 16:19pm    
Maybe update your original post with the change you implemented, it may help someone down the road.
[no name] 7-Dec-17 20:16pm    
Or simply delete the question.
Jerry Jeremiah 4-May-21 18:12pm    
Whenever you cast something you hide errors that the compiler would pick up. You should always write code so that you don't need to cast something. At the very least don't use C style casts.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900