If there are errors in the description or code, I hope to correct them.
Why does TCP need to unpack packets?
TCP uses the byte stream mode, that is, the byte sequence is transmitted in bytes. Then, we recv to a string of irregular byte streams. If you want to set rules for the non-Rule byte stream, you need to define a rule. This is the so-called "packet Rules ".
What is the encapsulation structure?
A packet is like a letter, which consists of an envelope and content. It consists of two parts. Network packets are composed of two parts: headers and data. The header domain is fixed and the data domain is not fixed. The header must contain two types of information: the operation code and the package length. Baotou may also contain other information, which depends on the situation. The operation code is the identifier of the network packet, which is similar to the event ID in the UI. Some of the operation codes have only one level, and some have two or even multiple levels of operation codes. The design also depends on the situation. However, after the bottom-layer operations are fixed, they are basically unable to work, it's like building a house and moving the foundation again.
The following is the pseudocode of the network data packet:
Struct NetPacket
{
Baotou;
Data;
}; The following is the pseudocode of the Baotou:
Struct NetPacketHeader
{
Operation Code;
Package length;
};
A problem exists in the package receiving (stick package, half package)
In actual network conditions, network transmission is often unreliable, so packet loss may occur. For this reason, TCP has a retransmission mechanism. For the receiver, the data in the data stream it receives may not be a complete data packet, or only a part of the data packet, or other data packets are attached. Therefore, the receiver also needs to subcontract the data of the received data stream.
Server Client logic description
The service waits for a client connection. After the client is connected, the server sends five data packets to the client. The client receives and unpacks the data from the server and then performs corresponding logical processing.
Precautions
1. The server client is blocked, not a non-blocking socket, for simplicity;
2. When the client receives five data packets, it proactively disconnects from the server. This is a hard code;
3. Blocking sockets do not need to process data packets in this way. They are mainly applied to non-blocking sockets.
Server CPP Code:
# Include "stdafx. h"
# Include "TCPServer. h"
TCPServer: TCPServer ()
: MServerSocket (INVALID_SOCKET)
{
// Create a socket
MServerSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_IP );
If (mServerSocket = INVALID_SOCKET)
{
Std: cout <"failed to create socket! "<Std: endl;
Return;
}
// Fill in the server IP address and port number
MServerAddr. sin_family = AF_INET;
MServerAddr. sin_addr.s_addr = INADDR_ANY;
MServerAddr. sin_port = htons (u_short) SERVER_PORT );
// Bind the IP address and port
If (: bind (mServerSocket, (sockaddr *) & mServerAddr, sizeof (mServerAddr) = SOCKET_ERROR)
{
Std: cout <"failed to bind IP address and port! "<Std: endl;
Return;
}
// Listen to client requests. The maximum number of simultaneous connections is set to 10.
If (: listen (mServerSocket, SOMAXCONN) = SOCKET_ERROR)
{
Std: cout <"listening port failed! "<Std: endl;
Return;
}
Std: cout <"TCP server started successfully! "<Std: endl;
}
TCPServer ::~ TCPServer ()
{
: Closesocket (mServerSocket );
Std: cout <"TCP Server Disabled successfully! "<Std: endl;
}
Void TCPServer: run ()
{
// Receive client connection
AcceptClient ();
Int nCount = 0;
For (;;)
{
If (mAcceptSocket = INVALID_SOCKET)
{
Std: cout <"the client proactively disconnects! "<Std: endl;
Break;
}
// Send data packets
NetPacket_Test1 msg;
Msg. nIndex = nCount;
Strncpy (msg. arrMessage, "[1] [2] [3] ", sizeof (msg. arrMessage ));
Bool bRet = SendData (NET_TEST1, (const char *) & msg, sizeof (msg ));
If (bRet)
{
Std: cout <"data sent successfully! "<Std: endl;
}
Else
{
Std: cout <"failed to send data! "<Std: endl;
Break;
}
++ NCount;
}
}
Void TCPServer: closeClient ()
{
// Determine whether the socket is valid
If (mAcceptSocket = INVALID_SOCKET) return;
// Close the client socket
: Closesocket (mAcceptSocket );
Std: cout <"the client socket is closed! "<Std: endl;
}
Void TCPServer: acceptClient ()
{
// In blocking mode, wait for receiving Client Connection
Int nAcceptAddrLen = sizeof (mAcceptAddr );
MAcceptSocket =: accept (mServerSocket, (struct sockaddr *) & mAcceptAddr, & nAcceptAddrLen );
Std: cout <"Accept Client IP:" <inet_ntoa (mAcceptAddr. sin_addr) <std: endl;
}
Bool TCPServer: SendData (unsigned short nOpcode, const char * pDataBuffer, const unsigned int & nDataSize)
{
NetPacketHeader * pHead = (NetPacketHeader *) m_cbSendBuf;
PHead-> wOpcode = nOpcode;
// Data packets
If (nDataSize> 0) & (pDataBuffer! = 0 ))
{
CopyMemory (pHead + 1, pDataBuffer, nDataSize );
}
// Send a message
Const unsigned short nSendSize = nDataSize + sizeof (NetPacketHeader );
PHead-> wDataSize = nSendSize;
Int ret =: send (mAcceptSocket, m_cbSendBuf, nSendSize, 0 );
Return (ret> 0 )? True: false;
}
Client CPP Code:
# Include "stdafx. h"
# Include "TCPClient. h"
TCPClient: TCPClient ()
{
Memset (m_cbRecvBuf, 0, sizeof (m_cbRecvBuf ));
M_nRecvSize = 0;
// Create a socket
MServerSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_IP );
If (mServerSocket = INVALID_SOCKET)
{
Std: cout <"failed to create socket! "<Std: endl;
Return;
}
// Fill in the server IP address and port number
MServerAddr. sin_family = AF_INET;
MServerAddr. sin_addr.s_addr = inet_addr (SERVER_IP );
MServerAddr. sin_port = htons (u_short) SERVER_PORT );
//