Click here to Skip to main content
15,890,186 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,
I am using simple TCP/IP applications that is include 2 parts:
Server:
C++
#pragma comment(lib, "Ws2_32.lib")

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

using namespace std;

// Ok at first I am going to do some WinSock standard stuff
// If you don`t understand it watch my other tutorials

SOCKADDR_IN addr;

SOCKET sListen;
SOCKET sConnect;
SOCKET* Connections;

int addrlen = sizeof(addr);
int ConCounter = 0;

struct Buffer
{
	int ID;
	char Message[256];
};

int ServerThread(int ID)
{
	Buffer sbuffer;

	char* Recv = new char[256];
	ZeroMemory(Recv, 256);

	// In Send we will copy the content of the struct
	// and after this we will send "Send" to the client
	char* Send = new char[sizeof(Buffer)];
	ZeroMemory(Send, sizeof(Buffer));

	for(;; Sleep(10))
	{
		// Same here!
		if(recv(Connections[ID], Recv, 256, NULL))
		{
			sbuffer.ID = ID;
			memcpy(sbuffer.Message, Recv, 256);
			memcpy(Send, &sbuffer, sizeof(Buffer));

			for(int a = 0; a != ConCounter; a++)
			{
				if(Connections[a] == Connections[ID])
				{

				}
				else
				{
					send(Connections[a], Send, sizeof(Buffer), NULL);
				}
			}
			ZeroMemory(Recv, 256);
		}
	}

	return 0;
}

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

	return RetVal;
}

int main()
{
	int RetVal = 0;
	RetVal = InitWinSock();
	if(RetVal != 0)
	{
		MessageBoxA(NULL, "Winsock startup failed", "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("66.96.201.81");
	addr.sin_port        = htons(1234);
	addr.sin_family      = AF_INET;

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

	for(;; Sleep(50))
	{
		if(sConnect = accept(sListen, (SOCKADDR*)&addr, &addrlen))
		{
			Connections[ConCounter] = sConnect;

			char* ID = new char[64];
			ZeroMemory(ID, sizeof(ID));

			itoa(ConCounter, ID, 10);
			send(Connections[ConCounter], ID, sizeof(ID), NULL);

			ConCounter = ConCounter + 1;
			CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE) ServerThread, (LPVOID)(ConCounter - 1), NULL, NULL);
		}
	}

	return 0;
}


And Clients:
C++
#pragma comment(lib, "Ws2_32.lib")

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

using namespace std;


SOCKADDR_IN addr;

SOCKET sConnect;

// For this we need to send two information at one time:
// 1. The main message
// 2. The ID

// To send more than one information I will use a struct
struct Buffer
{
	int ID;
	char Message[256];
};

int ClientThread()
{
	Buffer sbuffer;

	char buffer[sizeof(sbuffer)] = {0};

	for(;; Sleep(10))
	{
		// The server will send a struct to the client
		// containing message and ID
		// But send only accepts a char as buffer parameter
		// so here we need to recv a char buffer and then
		// we copy the content of this buffer to our struct
		if(recv(sConnect, buffer, sizeof(sbuffer), NULL))
		{
			memcpy(&sbuffer, buffer, sizeof(sbuffer));
			cout << "<Client " << sbuffer.ID << ":> " << sbuffer.Message <<endl;
		}
	}

	return 0;
}

int main()
{
	system("cls");

	int RetVal = 0;

	WSAData wsaData;
	WORD DllVersion = MAKEWORD(2,1);
	RetVal = WSAStartup(DllVersion, &wsaData);
	if(RetVal != 0)
	{
		MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
		exit(1);
	}

	sConnect = socket(AF_INET, SOCK_STREAM, NULL);

	addr.sin_addr.s_addr = inet_addr("66.96.201.81");
	addr.sin_port        = htons(1234);
	addr.sin_family      = AF_INET;

	cout << "Connect to Masterserver? [ENTER]" <<endl;
	getchar();
	RetVal = connect(sConnect, (SOCKADDR*)&addr, sizeof(addr));

	if(RetVal != 0)
	{
		MessageBoxA(NULL, "Could not connect to server", "Error", MB_OK | MB_ICONERROR);
		main();
	}
	else
	{
		int ID;
		char* cID = new char[64];
		ZeroMemory(cID, 64);

		recv(sConnect, cID, 64, NULL);
		ID = atoi(cID);

		cout << "Connected" <<endl;
		cout << "You are Client No: " << ID <<endl;

        CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE) ClientThread, NULL, NULL, NULL);
		
		for(;; Sleep(10))
		{
			char* buffer = new char[256];
			ZeroMemory(buffer, 256);

			cin >> buffer;
			getchar();
			
			send(sConnect, buffer, 256, NULL);
		}
	}

	return 0;
}


Applications work good. I have only one problem here.
When in client1 for example I write "How are you?" and press enter, in client2 instead it write exactly ""How are you?" and in one line, it parsing that and write in more lines word to word as below:
How
are
you
?
How I can fix this?
Regards,
Posted

TCP is a byte stream oriented protocol and NOT message oriented. You assume that you write "How are you?" as a message but TCP won't handle this as a message, instead it handles this as a byte sequence and the other side will receive this as a byte sequence that can be broken between every two bytes. If you want to send messages then you have to insert delimiters (for example zero characters into the byte stream and on the receiver side you have to collect bytes into a buffer as the bytes are flowing in and when you encounter a delimiter character you call your message handler with the whole received message.

If you write this:

"Message1" 0 "Message2" 0

Then you may receive it byte by byte or like this:

"Mess"
"a"
"ge"
"1" 0 "M" // at this point you call your message handler with "Message1" and you leave only the "M" in the buffer that is the beginning of the next message.
"essage2"
0 // you call your message handler function with "Message2"
 
Share this answer
 
Comments
Rezame 14-Oct-13 8:38am    
So what is solution for this?
How can get whole string in another client side?
[no name] 14-Oct-13 8:56am    
This answer is telling you how. You must add some delimiter char(s) to your send buffer before message is sent and then reconstruct the received message in the receive buffer while watching for the delimiter(s). That is how you know the whole message is received.
Don't send a newline with every received message. The data you read on a recv call may not be the complete message sent from the server.
 
Share this answer
 

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