TCP/IP 网络数据封包和解包
生活随笔
收集整理的這篇文章主要介紹了
TCP/IP 网络数据封包和解包
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
這是一個網(wǎng)上的代碼;下面列出資料并簡略分析代碼;
.
?
TCP/IP 網(wǎng)絡(luò)數(shù)據(jù)以流的方式傳輸,數(shù)據(jù)流是由包組成,如何判定接收方收到的包是否是一個完整的包就要在發(fā)送時對包進行處理,這就是封包技術(shù),將包處理成包頭,包體
?
包頭是包的開始標記,整個包的大小就是包的結(jié)束標記。接收方只要按同樣的方式解包即可,下面是一個網(wǎng)絡(luò)服務(wù)端和客戶端程序代碼。
?
客戶端和服務(wù)端共享的文件:(數(shù)據(jù)包的定義)?
01.#pragma once ?
02. ?
03. ?
04.#define NET_PACKET_DATA_SIZE 1024 ??
05.#define NET_PACKET_SIZE (sizeof(NetPacketHeader) + NET_PACKET_DATA_SIZE) * 10 ?
06. ?
07. ?
08./// 網(wǎng)絡(luò)數(shù)據(jù)包包頭 ?
09.struct NetPacketHeader ?
10.{ ?
11. ? ?unsigned short ? ? ?wDataSize; ?///< 數(shù)據(jù)包大小,包含封包頭和封包數(shù)據(jù)大小 ?
12. ? ?unsigned short ? ? ?wOpcode; ? ?///< 操作碼 ?
13.}; ?
14. ?
15./// 網(wǎng)絡(luò)數(shù)據(jù)包 ?
16.struct NetPacket ?
17.{ ?
18. ? ?NetPacketHeader ? ? Header; ? ? ? ? ? ? ? ? ? ? ? ? ///< 包頭 ?
19. ? ?unsigned char ? ? ? Data[NET_PACKET_DATA_SIZE]; ? ? ///< 數(shù)據(jù) ?
20.}; ?
21. ?
22. ?
23. ?
24.// ?
25. ?
26. ?
27./// 網(wǎng)絡(luò)操作碼 ?
28.enum eNetOpcode ?
29.{ ?
30. ? ?NET_TEST1 ? ? ? ? ? = 1, ?
31.}; ?
32. ?
33./// 測試1的網(wǎng)絡(luò)數(shù)據(jù)包定義 ?
34.struct NetPacket_Test1 ?
35.{ ?
36. ? ?int ? ? nIndex; ?
37. ? ?char name[20]; ?
38. ? ?char sex[20]; ?
39. ? ?int age; ?
40. ? ?char ? ?arrMessage[512]; ?
41.}; ?
服務(wù)端:
[cpp] view plaincopyprint?
01.#pragma once ?
02. ?
03.class TCPServer ?
04.{ ?
05.public: ?
06. ? ?TCPServer(); ?
07. ? ?virtual ~TCPServer(); ?
08. ?
09.public: ?
10. ? ?void run(); ?
11. ?
12. ? ?/// 接受客戶端接入 ?
13. ? ?void acceptClient(); ?
14. ?
15. ? ?/// 關(guān)閉客戶端 ?
16. ? ?void closeClient(); ?
17. ?
18. ? ?/// 發(fā)送數(shù)據(jù) ?
19. ? ?bool SendData(unsigned short nOpcode, const char* pDataBuffer, const unsigned int& nDataSize); ?
20. ?
21.private: ?
22. ? ?SOCKET ? ? ?mServerSocket; ?///< 服務(wù)器套接字句柄 ?
23. ? ?sockaddr_in mServerAddr; ? ?///< 服務(wù)器地址 ?
24. ?
25. ? ?SOCKET ? ? ?mAcceptSocket; ?///< 接受的客戶端套接字句柄 ?
26. ? ?sockaddr_in mAcceptAddr; ? ?///< 接收的客戶端地址 ?
27. ?
28. ? ?char ? ? ? ?m_cbSendBuf[NET_PACKET_SIZE]; ?
29.}; ?
[cpp] view plaincopyprint?
01.#include "stdafx.h" ?
02. ?
03. ?
04.TCPServer::TCPServer() ?
05.: mServerSocket(INVALID_SOCKET) ?
06.{ ?
07. ? ?// 創(chuàng)建套接字 ?
08. ? ?mServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); ?
09. ? ?if (mServerSocket == INVALID_SOCKET) ?
10. ? ?{ ?
11. ? ? ? ?std::cout << "創(chuàng)建套接字失敗!" << std::endl; ?
12. ? ? ? ?return; ?
13. ? ?} ?
14. ?
15. ? ?// 填充服務(wù)器的IP和端口號 ?
16. ? ?mServerAddr.sin_family ? ? ?= AF_INET; ?
17. ? ?mServerAddr.sin_addr.s_addr = INADDR_ANY; ?
18. ? ?mServerAddr.sin_port ? ? ? ?= htons((u_short)SERVER_PORT); ?
19. ?
20. ? ?// 綁定IP和端口 ?
21. ? ?if ( ::bind(mServerSocket, (sockaddr*)&mServerAddr, sizeof(mServerAddr)) == SOCKET_ERROR) ?
22. ? ?{ ?
23. ? ? ? ?std::cout << "綁定IP和端口失敗!" << std::endl; ?
24. ? ? ? ?return; ?
25. ? ?} ?
26. ?
27. ? ?// 監(jiān)聽客戶端請求,最大同時連接數(shù)設(shè)置為10. ?
28. ? ?if ( ::listen(mServerSocket, SOMAXCONN) == SOCKET_ERROR) ?
29. ? ?{ ?
30. ? ? ? ?std::cout << "監(jiān)聽端口失敗!" << std::endl; ?
31. ? ? ? ?return; ?
32. ? ?} ?
33. ?
34. ? ?std::cout << "啟動TCP服務(wù)器成功!" << std::endl; ?
35.} ?
36. ?
37.TCPServer::~TCPServer() ?
38.{ ?
39. ? ?::closesocket(mServerSocket); ?
40. ? ?std::cout << "關(guān)閉TCP服務(wù)器成功!" << std::endl; ?
41.} ?
42. ?
43.void TCPServer::run() ?
44.{ ?
45. ? ?// 接收客戶端的連接 ?
46. ? ?acceptClient(); ?
47. ?
48. ? ?int nCount = 0; ?
49. ? ?for (;;) ?
50. ? ?{ ?
51. ? ? ? ?if (mAcceptSocket == INVALID_SOCKET) ??
52. ? ? ? ?{ ?
53. ? ? ? ? ? ?std::cout << "客戶端主動斷開了連接!" << std::endl; ?
54. ? ? ? ? ? ?break; ?
55. ? ? ? ?} ?
56. ?
57. ? ? ? ?// 發(fā)送數(shù)據(jù)包 ?
58. ? ? ? ?NetPacket_Test1 msg;//消息類型 ?
59. ? ? ? ?msg.nIndex = nCount; ?
60. ? ? ? ?msg.age=23; ?
61. ? ? ? ?strncpy(msg.arrMessage, "北京市朝陽區(qū)", sizeof(msg.arrMessage) ); ?
62. ? ? ? ?strncpy(msg.name, "天策", sizeof(msg.name) ); ?
63. ? ? ? ?strncpy(msg.sex, "男", sizeof(msg.sex) ); ?
64. ?
65. ? ? ? ?bool bRet = SendData(NET_TEST1, (const char*)&msg, sizeof(msg));//強制類型轉(zhuǎn)換為字符串類型 ?
66. ? ? ? ?if (bRet) ?
67. ? ? ? ?{ ?
68. ? ? ? ? ? ?std::cout << "發(fā)送數(shù)據(jù)成功!" << std::endl; ?
69. ? ? ? ?} ?
70. ? ? ? ?else ?
71. ? ? ? ?{ ?
72. ? ? ? ? ? ?std::cout << "發(fā)送數(shù)據(jù)失敗!" << std::endl; ?
73. ? ? ? ? ? ?break; ?
74. ? ? ? ?} ?
75. ?
76. ? ? ? ?++nCount; ?
77. ? ?} ?
78.} ?
79. ?
80.void TCPServer::closeClient() ?
81.{ ?
82. ? ?// 判斷套接字是否有效 ?
83. ? ?if (mAcceptSocket == INVALID_SOCKET) return; ?
84. ?
85. ? ?// 關(guān)閉客戶端套接字 ?
86. ? ?::closesocket(mAcceptSocket); ?
87. ? ?std::cout << "客戶端套接字已關(guān)閉!" << std::endl; ?
88.} ?
89. ?
90.void TCPServer::acceptClient() ?
91.{ ?
92. ? ?// 以阻塞方式,等待接收客戶端連接 ?
93. ? ?int nAcceptAddrLen = sizeof(mAcceptAddr); ?
94. ? ?mAcceptSocket = ::accept(mServerSocket, (struct sockaddr*)&mAcceptAddr, &nAcceptAddrLen); ?
95. ? ?std::cout << "接受客戶端IP:" << inet_ntoa(mAcceptAddr.sin_addr) << std::endl; ?
96.} ?
97. ?
98.bool TCPServer::SendData( unsigned short nOpcode, const char* pDataBuffer, const unsigned int& nDataSize ) ?
99.{ ?
100. ? ?NetPacketHeader* pHead = (NetPacketHeader*) m_cbSendBuf; ?
101. ? ?pHead->wOpcode = nOpcode;//操作碼 ?
102. ?
103. ? ?// 數(shù)據(jù)封包 ?
104. ? ?if ( (nDataSize > 0) && (pDataBuffer != 0) ) ?
105. ? ?{ ?
106. ? ? ? ?CopyMemory(pHead+1, pDataBuffer, nDataSize); ??
107. ? ?} ?
108. ?
109. ? ?// 發(fā)送消息 ?
110. ? ?const unsigned short nSendSize = nDataSize + sizeof(NetPacketHeader);//包的大小事發(fā)送數(shù)據(jù)的大小加上包頭大小 ?
111. ? ?pHead->wDataSize = nSendSize;//包大小 ?
112. ? ?int ret = ::send(mAcceptSocket, m_cbSendBuf, nSendSize, 0); ?
113. ? ?return (ret > 0) ? true : false; ?
114.} ?
[cpp] view plaincopyprint?
01.// testTCPServer.cpp : 定義控制臺應(yīng)用程序的入口點。 ?
02.// ?
03. ?
04.#include "stdafx.h" ?
05. ?
06. ?
07. ?
08.int _tmain(int argc, _TCHAR* argv[]) ?
09.{ ?
10. ? ?TCPServer server; ?
11. ? ?server.run(); ?
12. ?
13. ? ?system("pause"); ?
14. ? ?return 0; ?
15.} ?
客戶端:
[cpp] view plaincopyprint?
01.<span style="font-size: 14px;">#pragma once ?
02. ?
03.class TCPClient ?
04.{ ?
05.public: ?
06. ? ?TCPClient(); ?
07. ? ?virtual ~TCPClient(); ?
08. ?
09.public: ?
10. ? ?/// 主循環(huán) ?
11. ? ?void run(); ?
12. ?
13. ? ?/// 處理網(wǎng)絡(luò)消息 ?
14. ? ?bool OnNetMessage(const unsigned short& nOpcode, ??
15. ? ? ? ?const char* pDataBuffer, unsigned short nDataSize); ?
16. ?
17. ? ?bool OnNetPacket(NetPacket_Test1* pMsg); ?
18. ?
19.private: ?
20. ? ?SOCKET ? ? ? ? ? ? ?mServerSocket; ?///< 服務(wù)器套接字句柄 ?
21. ? ?sockaddr_in ? ? ? ? mServerAddr; ? ?///< 服務(wù)器地址 ?
22. ?
23. ? ?char ? ? ? ? ? ? ? ?m_cbRecvBuf[NET_PACKET_SIZE]; ?
24. ? ?char ? ? ? ? ? ? ? ?m_cbDataBuf[NET_PACKET_SIZE]; ?
25. ? ?int ? ? ? ? ? ? ? ? m_nRecvSize; ?
26.}; ?
27.</span> ?
?
[cpp] view plaincopyprint?
01.#include "stdafx.h" ?
02. ?
03. ?
04. ?
05.TCPClient::TCPClient() ?
06.{ ?
07. ? ?memset( m_cbRecvBuf, 0, sizeof(m_cbRecvBuf) ); ?
08. ? ?m_nRecvSize = 0; ?
09. ?
10. ? ?// 創(chuàng)建套接字 ?
11. ? ?mServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); ?
12. ? ?if (mServerSocket == INVALID_SOCKET) ?
13. ? ?{ ?
14. ? ? ? ?std::cout << "創(chuàng)建套接字失敗!" << std::endl; ?
15. ? ? ? ?return; ?
16. ? ?} ?
17. ?
18. ? ?// 填充服務(wù)器的IP和端口號 ?
19. ? ?mServerAddr.sin_family ? ? ?= AF_INET; ?
20. ? ?mServerAddr.sin_addr.s_addr = inet_addr(SERVER_IP); ?
21. ? ?mServerAddr.sin_port ? ? ? ?= htons((u_short)SERVER_PORT); ?
22. ?
23. ? ?// 連接到服務(wù)器 ?
24. ? ?if ( ::connect(mServerSocket, (struct sockaddr*)&mServerAddr, sizeof(mServerAddr))) ?
25. ? ?{ ?
26. ? ? ? ?::closesocket(mServerSocket); ?
27. ? ? ? ?std::cout << "連接服務(wù)器失敗!" << std::endl; ?
28. ? ? ? ?return; ??
29. ? ?} ?
30.} ?
31. ?
32.TCPClient::~TCPClient() ?
33.{ ?
34. ? ?::closesocket(mServerSocket); ?
35.} ?
36. ?
37.void TCPClient::run() ?
38.{ ?
39. ? ?int nCount = 0; ?
40. ? ?for (;;) ?
41. ? ?{ ?
42. ? ? ? ?// 接收數(shù)據(jù) ?
43. ? ? ? ?int nRecvSize = ::recv(mServerSocket, ?
44. ? ? ? ? ? ?m_cbRecvBuf+m_nRecvSize, ??
45. ? ? ? ? ? ?sizeof(m_cbRecvBuf)-m_nRecvSize, 0); ?
46. ? ? ? ?if (nRecvSize <= 0) ?
47. ? ? ? ?{ ?
48. ? ? ? ? ? ?std::cout << "服務(wù)器主動斷開連接!" << std::endl; ?
49. ? ? ? ? ? ?break; ?
50. ? ? ? ?} ?
51. ?
52. ? ? ? ?// 保存已經(jīng)接收數(shù)據(jù)的大小 ?
53. ? ? ? ?m_nRecvSize += nRecvSize; ?
54. ?
55. ? ? ? ?// 接收到的數(shù)據(jù)夠不夠一個包頭的長度 ?
56. ? ? ? ?while (m_nRecvSize >= sizeof(NetPacketHeader))//已經(jīng)收到一個完整的包,如果沒用收到一個完整的包,此處循環(huán)不執(zhí)行,繼續(xù)下一輪循環(huán) ?
57. ? ? ? ?{ ?
58. ? ? ? ? ? ?// 收夠5個包,主動與服務(wù)器斷開 ?
59. ? ? ? ? ? ?if (nCount >= 5) ?
60. ? ? ? ? ? ?{ ?
61. ? ? ? ? ? ? ? ?::closesocket(mServerSocket); ?
62. ? ? ? ? ? ? ? ?break; ?
63. ? ? ? ? ? ?} ?
64. ?
65. ? ? ? ? ? ?// 讀取包頭 ?
66. ? ? ? ? ? ?NetPacketHeader* pHead = (NetPacketHeader*) (m_cbRecvBuf); ?
67. ? ? ? ? ? ?const unsigned short nPacketSize = pHead->wDataSize; ?
68. ?
69. ? ? ? ? ? ?// 判斷是否已接收到足夠一個完整包的數(shù)據(jù) ?
70. ? ? ? ? ? ?if (m_nRecvSize < nPacketSize) ?
71. ? ? ? ? ? ?{ ?
72. ? ? ? ? ? ? ? ?// 還不夠拼湊出一個完整包 ?
73. ? ? ? ? ? ? ? ?break; ?
74. ? ? ? ? ? ?} ?
75. ?
76. ? ? ? ? ? ?// 拷貝到數(shù)據(jù)緩存 ?
77. ? ? ? ? ? ?CopyMemory(m_cbDataBuf, m_cbRecvBuf, nPacketSize); ?
78. ?
79. ? ? ? ? ? ?// 從接收緩存移除 ?
80. ? ? ? ? ? ?MoveMemory(m_cbRecvBuf, m_cbRecvBuf+nPacketSize, m_nRecvSize); ?
81. ? ? ? ? ? ?m_nRecvSize -= nPacketSize; ?
82. ?
83. ? ? ? ? ? ?// 解密數(shù)據(jù),以下省略一萬字 ?
84. ? ? ? ? ? ?// ... ?
85. ?
86. ? ? ? ? ? ?// 分派數(shù)據(jù)包,讓應(yīng)用層進行邏輯處理 ?
87. ? ? ? ? ? ?pHead = (NetPacketHeader*) (m_cbDataBuf); ?
88. ? ? ? ? ? ?const unsigned short nDataSize = nPacketSize - (unsigned short)sizeof(NetPacketHeader); ?
89. ? ? ? ? ? ?OnNetMessage(pHead->wOpcode, m_cbDataBuf+sizeof(NetPacketHeader), nDataSize); ?
90. ?
91. ? ? ? ? ? ?++nCount; ?
92. ? ? ? ?} ?
93. ? ?} ?
94. ?
95. ? ?std::cout << "已經(jīng)和服務(wù)器斷開連接!" << std::endl; ?
96.} ?
97. ?
98.bool TCPClient::OnNetMessage( const unsigned short& nOpcode, ??
99. ? ? ? ? ? ? ? ? ? ? ? ? ? ? const char* pDataBuffer, unsigned short nDataSize ) ?
100.{ ?
101. ? ?switch (nOpcode) ?
102. ? ?{ ?
103. ? ?case NET_TEST1: ?
104. ? ? ? ?{ ?
105. ? ? ? ? ? ?NetPacket_Test1* pMsg = (NetPacket_Test1*) pDataBuffer; ?
106. ? ? ? ? ? ?return OnNetPacket(pMsg); ?
107. ? ? ? ?} ?
108. ? ? ? ?break; ?
109. ?
110. ? ?default: ?
111. ? ? ? ?{ ?
112. ? ? ? ? ? ?std::cout << "收取到未知網(wǎng)絡(luò)數(shù)據(jù)包:" << nOpcode << std::endl; ?
113. ? ? ? ? ? ?return false; ?
114. ? ? ? ?} ?
115. ? ? ? ?break; ?
116. ? ?} ?
117.} ?
118. ?
119.bool TCPClient::OnNetPacket( NetPacket_Test1* pMsg ) ?
120.{ ?
121. ? ?std::cout << "索引:" << pMsg->nIndex << " ?字符串:" << pMsg->arrMessage <<"name:"<<pMsg->name<<"sex:"<<pMsg->sex<<"age:"<<pMsg->age<< std::endl; ?
122. ? ?return true; ?
123.} ?
[cpp] view plaincopyprint?
01.#include "stdafx.h" ?
02. ?
03. ?
04.int _tmain(int argc, _TCHAR* argv[]) ?
05.{ ?
06. ? ?TCPClient client; ?
07. ? ?client.run(); ?
08. ?
09. ? ?system("pause"); ?
10. ? ?return 0; ?
11.} ?
下面分析一下其代碼;
首先這是一個VC++程序;因為,_tmain是VC++下的類似于C的main的東東;
首先定義包頭結(jié)構(gòu)體,包結(jié)構(gòu)體,操作碼枚舉;
首先運行客戶端;在客戶端的構(gòu)造函數(shù)中,分配接收緩沖區(qū),創(chuàng)建套接字,連接服務(wù)器;
run()函數(shù)運行,接收并保存包,調(diào)用OnNetMessage()進行處理;
OnNetMessage()中,如果nOpcode是NET_TEST1,調(diào)用OnNetPacket();
OnNetPacket()中輸出包的內(nèi)容;
服務(wù)端的構(gòu)造函數(shù),創(chuàng)建套接字,綁定IP和端口,監(jiān)聽客戶端請求;
run()中,接收客戶端連接,發(fā)送數(shù)據(jù)包;
服務(wù)端也是一個單獨的控制臺應(yīng)用程序;單獨啟動;
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的TCP/IP 网络数据封包和解包的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 系统编程
- 下一篇: ODBC + WIN32 API 访问M