Several ways of C++ Socket network data transmission

When C++ Socket transmits network data, the data is generally a char type character array. In addition, there are some methods to transmit the data types defined by ourselves

  1. Custom structure
  2. Json serialization
  3. Define Class object
1. Structure

Define a structure, for example:

struct DataPack
{
	int age;
	string name;
};

When sending data, process the data and forcibly convert the pointer of DataPack type to the pointer of char type, as follows:

DataPack da = { 20, "anthony" };
send(cSock, (char *)&da, sizeof(da), 0);

When receiving data, define a structure of the same type to parse the string:

DataPack tmp;
		int nlen = recv(sock, (char *)&tmp, 128, 0);
		if (nlen > 0)
		{
			cout << "Received data:" << tmp.age << "	" << tmp.name << endl;
		}

Alternatively:

int nlen = recv(sock, recvBuf, 128, 0);    // recvBuf is the buffer for receiving data
if (nlen > 0)
{
	DataPack* da = (DataPack*)recvBuf;     // Convert char type pointer to DataPack type pointer
	cout << "Received data:" << tmp->age << "	" << tmp->name << endl;
}
1.1 network data message

In order to reduce errors in data transmission and enhance stability, we can use network data message:

Similar to the message format of network protocol, the message has two parts: packet header and packet body, which are regarded as the basic unit of network message

Packet header: describes the size and function of the packet sent this time

Packet header: the data part of the packet

Next, we define a message structure for login and logout:

// The role of messages or commands in the header (login, exit)
enum CMD
{
	CMD_LOGIN,
	CMD_LogOut,
	CMD_ERROR
};
// Baotou
struct DataHeader
{
	int lenth;
	int cmd;
};
// Login data
struct Login
{
	char UserName[32];
	char passWord[32];
};
// Login results
struct LoginSucceed
{
	int result;
};
// Log out
struct LogOut
{
	char UserName[32];
};
// Results of logout
struct LogOutSucceed
{
	int result;
};

Each time data is sent, the packet header is sent first, and the data is sent in the data sending part

Server implementation:

// After accepting the connection from the client
cSock = accept(sock, (sockaddr*)&clientAddr, &nAddrLen);
	if (INVALID_SOCKET == cSock)
	{
		cout << "Error, invalid client received SOCKET..." << endl;
	}
	cout << "New client join:" << inet_ntoa(clientAddr.sin_addr) << endl;
	//5 send sends data to the client
	

	while (true)
	{
		DataHeader header = {};
		int nlen = recv(cSock, (char*)&header, sizeof(header), 0);
		if (nlen <= 0)
		{
			cout << "Client exit..." << endl;
			break;
		}
		cout << "Command received:" << header.cmd << "	Data length:" << header.lenth << endl;
		//Processing requests
		switch (header.cmd)
		{
		case CMD_LOGIN:
		{
			Login login;
			int nlen = recv(cSock, (char*)&login, sizeof(login), 0);
			LoginSucceed ret = { 1 };
			send(cSock, (char*)&header, sizeof(header), 0);
			send(cSock, (char*)&ret, sizeof(ret), 0);
		}
		break;
		case CMD_LogOut:
		{
			LogOut logout;
			recv(cSock, (char*)&logout, sizeof(logout), 0);
			LogOutSucceed ret = { 1 };
			send(cSock, (char*)&header, sizeof(header), 0);
			send(cSock, (char*)&ret, sizeof(ret), 0);
		}
		break;
		default:
			header.cmd = CMD_ERROR;
			header.lenth = 0;
			send(cSock, (char*)&header, sizeof(header), 0);
			break;
		}
	}

Client implementation:

if (SOCKET_ERROR == connect(sock, (sockaddr*)&sin, sizeof(sockaddr_in)))
	{
		cout << "Failed to establish connection..." << endl;
	}
	else {
		cout << "Connection established successfully..." << endl;
	}

	while (true)
	{
		string comBuf;
		cin >> comBuf;
		if (comBuf == "exit")
		{
			break;
		}
		else if (comBuf == "login") {
			Login login = { "anthony", "chen" };
			DataHeader dh = {sizeof(login), CMD_LOGIN};

			//Send request command to server
			send(sock, (char*)&dh, sizeof(dh), 0);
			send(sock, (char*)&login, sizeof(login), 0);
			//Receiving server return data
			DataHeader retHeader;
			LoginSucceed loginRet;
			recv(sock, (char*)&retHeader, sizeof(retHeader), 0);
			recv(sock, (char*)&loginRet, sizeof(loginRet), 0);
			cout << "LoginSucceed: " << loginRet.result << endl;
		}
		else if (comBuf == "logout") {
			LogOut logout = { "anthony" };
			DataHeader dh = { sizeof(logout), CMD_LogOut};
			//Send request command to server
			send(sock, (char*)&dh, sizeof(dh), 0);
			send(sock, (char*)&logout, sizeof(logout), 0);
			//Receiving server return data
			DataHeader retHeader;
			LogOutSucceed logoutRet;
			recv(sock, (char*)&retHeader, sizeof(retHeader), 0);
			recv(sock, (char*)&logoutRet, sizeof(logoutRet), 0);
			cout << "LogOutSucceed: " << logoutRet.result << endl;
		}
		else {
			cout << "Invalid command, please re-enter:" << endl;
		}
	}

1.2 change from multiple sending and receiving messages to one sending and receiving

In order to reduce errors, we can encapsulate multiple structures by aggregation or inheritance, as follows:

// The inheritance method is used here. In addition, you can also directly define another structure in one structure
// For example: struct Login{DataHeader header; char UserName[32]; char passWord[32];}
enum CMD
{
	CMD_LOGIN,
	CMD_LogOut,
	CMD_LOGIN_SU,
	CMD_LOGOUT_SU,
	CMD_ERROR
};
struct DataHeader
{
	int lenth;
	int cmd;
};
// Data Package
struct Login : public DataHeader
{
	Login()
	{
		lenth = sizeof(Login);
		cmd = CMD_LOGIN;
	}
	char UserName[32];
	char passWord[32];
};

struct LoginSucceed : public DataHeader
{
	LoginSucceed()
	{
		lenth = sizeof(LoginSucceed);
		cmd = CMD_LOGIN_SU;
	}
	int result;
};
struct LogOut : public DataHeader
{
	LogOut()
	{
		lenth = sizeof(LogOut);
		cmd = CMD_LogOut;
	}
	char UserName[32];
};
struct LogOutSucceed : public DataHeader
{
	LogOutSucceed()
	{
		lenth = sizeof(LogOutSucceed);
		cmd = CMD_LOGOUT_SU;
	}
	int result;
};

Server implementation:

	while (true)
	{
		/*DataHeader header = {};
		int nlen = recv(cSock, (char*)&header, sizeof(header), 0);*/
		Login login;
		int nlen = recv(cSock, (char*)&login, sizeof(login), 0);
		if (nlen <= 0)
		{
			cout << "Client exit..." << endl;
			break;
		}
		//Processing requests
		switch (login.cmd)
		{
		case CMD_LOGIN:
		{
			/*Login login;
			recv(cSock, (char*)&login, sizeof(login), 0);*/
			cout << "Command received: CMD_LOGIN" << "	Data length:" << login.lenth << "    UserName: " << login.UserName << "    PassWord: " << login.passWord << endl;

			LoginSucceed ret;
			send(cSock, (char*)&ret, sizeof(ret), 0);
		}
		break;
		case CMD_LogOut:
		{
			/*LogOut logout;
			recv(cSock, (char*)&logout, sizeof(logout), 0);*/
			cout << "Command received: CMD_LOGIN" << "	Data length:" << login.lenth << "    UserName: " << login.UserName << endl;
			LogOutSucceed ret;
			send(cSock, (char*)&ret, sizeof(ret), 0);
		}
		break;
		default:
			login.cmd = CMD_ERROR;
			login.lenth = 0;
			send(cSock, (char*)&login, sizeof(login), 0);
			break;
		}
	}

client:

	while (true)
	{
		string comBuf;
		cin >> comBuf;
		if (comBuf == "exit")
		{
			break;
		}
		else if (comBuf == "login") {
			Login login;
			strcpy(login.UserName, "anthony");
			strcpy(login.passWord, "chen");

			//Send request command to server
			send(sock, (char*)&login, sizeof(login), 0);
			//Receiving server return data
			LoginSucceed loginRet;
			recv(sock, (char*)&loginRet, sizeof(loginRet), 0);
			cout << "LoginSucceed: " << loginRet.result << endl;
		}
		else if (comBuf == "logout") {
			LogOut logout;
			strcpy(logout.UserName, "anthony");
			//Send request command to server
			send(sock, (char*)&logout, sizeof(logout), 0);
			//Receiving server return data
			LogOutSucceed logoutRet;
			recv(sock, (char*)&logoutRet, sizeof(logoutRet), 0);
			cout << "LogOutSucceed: " << logoutRet.result << endl;
		}
		else {
			cout << "Invalid command, please re-enter:" << endl;
		}
	}
2. Use Jason (try later)

The full name of JSON is JavaScript Object Notation, which is a lightweight data transmission format. When C + + processes JSON format data, it needs to use a third-party library. The famous one is jsoncpp. The download address is:

3. Define Class object

Similar to structure, when transferring custom object data, you can convert the type of pointer.

Tags: network socket C++ Network Communications

Posted by dacs on Mon, 18 Apr 2022 18:47:59 +0930