这是一个网上的代码;下面列出资料并简略分析代码;

TCP/IP 网络数据封包和解包 
.
 
TCP/IP 网络数据以流的方式传输,数据流是由包组成,如何判定接收方收到的包是否是一个完整的包就要在发送时对包进行处理,这就是封包技术,将包处理成包头,包体
 
包头是包的开始标记,整个包的大小就是包的结束标记。接收方只要按同样的方式解包即可,下面是一个网络服务端和客户端程序代码。
 
客户端和服务端共享的文件:(数据包的定义)

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./// 网络数据包包头  
09.struct NetPacketHeader  
10.{  
11.    unsigned short      wDataSize;  ///< 数据包大小,包含封包头和封包数据大小  
12.    unsigned short      wOpcode;    ///< 操作码  
13.};  
14.  
15./// 网络数据包  
16.struct NetPacket  
17.{  
18.    NetPacketHeader     Header;                         ///< 包头  
19.    unsigned char       Data[NET_PACKET_DATA_SIZE];     ///< 数据  
20.};  
21.  
22.  
23.  
24.//  
25.  
26.  
27./// 网络操作码  
28.enum eNetOpcode  
29.{  
30.    NET_TEST1           = 1,  
31.};  
32.  
33./// 测试1的网络数据包定义  
34.struct NetPacket_Test1  
35.{  
36.    int     nIndex;  
37.    char name[20];  
38.    char sex[20];  
39.    int age;  
40.    char    arrMessage[512];  
41.};

服务端:

[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.    /// 关闭客户端  
16.    void closeClient();  
17.  
18.    /// 发送数据  
19.    bool SendData(unsigned short nOpcode, const char* pDataBuffer, const unsigned int& nDataSize);  
20.  
21.private:  
22.    SOCKET      mServerSocket;  ///< 服务器套接字句柄  
23.    sockaddr_in mServerAddr;    ///< 服务器地址  
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.    // 创建套接字  
08.    mServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);  
09.    if (mServerSocket == INVALID_SOCKET)  
10.    {  
11.        std::cout << "创建套接字失败!" << std::endl;  
12.        return;  
13.    }  
14.  
15.    // 填充服务器的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.    // 监听客户端请求,最大同时连接数设置为10.  
28.    if ( ::listen(mServerSocket, SOMAXCONN) == SOCKET_ERROR)  
29.    {  
30.        std::cout << "监听端口失败!" << std::endl;  
31.        return;  
32.    }  
33.  
34.    std::cout << "启动TCP服务器成功!" << std::endl;  
35.}  
36.  
37.TCPServer::~TCPServer()  
38.{  
39.    ::closesocket(mServerSocket);  
40.    std::cout << "关闭TCP服务器成功!" << 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.        // 发送数据包  
58.        NetPacket_Test1 msg;//消息类型  
59.        msg.nIndex = nCount;  
60.        msg.age=23;  
61.        strncpy(msg.arrMessage, "北京市朝阳区", 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));//强制类型转换为字符串类型  
66.        if (bRet)  
67.        {  
68.            std::cout << "发送数据成功!" << std::endl;  
69.        }  
70.        else  
71.        {  
72.            std::cout << "发送数据失败!" << 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.    // 关闭客户端套接字  
86.    ::closesocket(mAcceptSocket);  
87.    std::cout << "客户端套接字已关闭!" << 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.    // 数据封包  
104.    if ( (nDataSize > 0) && (pDataBuffer != 0) )  
105.    {  
106.        CopyMemory(pHead+1, pDataBuffer, nDataSize);   
107.    }  
108.  
109.    // 发送消息  
110.    const unsigned short nSendSize = nDataSize + sizeof(NetPacketHeader);//包的大小事发送数据的大小加上包头大小  
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 : 定义控制台应用程序的入口点。  
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.    /// 主循环  
11.    void run();  
12.  
13.    /// 处理网络消息  
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;  ///< 服务器套接字句柄  
21.    sockaddr_in         mServerAddr;    ///< 服务器地址  
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.    // 创建套接字  
11.    mServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);  
12.    if (mServerSocket == INVALID_SOCKET)  
13.    {  
14.        std::cout << "创建套接字失败!" << std::endl;  
15.        return;  
16.    }  
17.  
18.    // 填充服务器的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.    // 连接到服务器  
24.    if ( ::connect(mServerSocket, (struct sockaddr*)&mServerAddr, sizeof(mServerAddr)))  
25.    {  
26.        ::closesocket(mServerSocket);  
27.        std::cout << "连接服务器失败!" << 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.        // 接收数据  
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 << "服务器主动断开连接!" << std::endl;  
49.            break;  
50.        }  
51.  
52.        // 保存已经接收数据的大小  
53.        m_nRecvSize += nRecvSize;  
54.  
55.        // 接收到的数据够不够一个包头的长度  
56.        while (m_nRecvSize >= sizeof(NetPacketHeader))//已经收到一个完整的包,如果没用收到一个完整的包,此处循环不执行,继续下一轮循环  
57.        {  
58.            // 收够5个包,主动与服务器断开  
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.            // 判断是否已接收到足够一个完整包的数据  
70.            if (m_nRecvSize < nPacketSize)  
71.            {  
72.                // 还不够拼凑出一个完整包  
73.                break;  
74.            }  
75.  
76.            // 拷贝到数据缓存  
77.            CopyMemory(m_cbDataBuf, m_cbRecvBuf, nPacketSize);  
78.  
79.            // 从接收缓存移除  
80.            MoveMemory(m_cbRecvBuf, m_cbRecvBuf+nPacketSize, m_nRecvSize);  
81.            m_nRecvSize -= nPacketSize;  
82.  
83.            // 解密数据,以下省略一万字  
84.            // ...  
85.  
86.            // 分派数据包,让应用层进行逻辑处理  
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 << "已经和服务器断开连接!" << 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 << "收取到未知网络数据包:" << 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的东东;

首先定义包头结构体,包结构体,操作码枚举;

首先运行客户端;在客户端的构造函数中,分配接收缓冲区,创建套接字,连接服务器;
run()函数运行,接收并保存包,调用OnNetMessage()进行处理;
OnNetMessage()中,如果nOpcode是NET_TEST1,调用OnNetPacket();
OnNetPacket()中输出包的内容;

服务端的构造函数,创建套接字,绑定IP和端口,监听客户端请求;
run()中,接收客户端连接,发送数据包;
服务端也是一个单独的控制台应用程序;单独启动;

TCP/IP 网络数据封包和解包相关推荐

  1. TCP/IP网络协议栈:以太网数据包结构、802.3、MTU

    <TCP/IP网络协议栈:以太网数据包结构.802.3> <TCP/IP网络协议栈:ARP协议详解> <TCP / IP攻击:ARP缓存中毒的基本原理.TCP序列号预测和 ...

  2. TCP利用封包和解包解决“粘包”问题

    本文参考自徐晓鑫<后台开发>,给出一个可实际应用的demo,该demo核心在于封包和解包的思想,以及自定义发送.接收数据. 一.TCP粘包现象 what? TCP是个"流&quo ...

  3. 命名数据网络(NDN)与TCP/IP网络

    之前面试时遇到一个十分有趣的开放性的问题:  当前TCP/IP协议存在哪些问题?如何改进? 当时没有回答好,然后提到了NDN可以针对TCP/IP做出改进,但是在行家面前就漏洞百出,一是对TCP/IP网 ...

  4. TCP/IP网络编程:P3->地址族与数据序列

    本系列文章为<TCP/IP网络编程----尹圣雨>学习笔记,前面的系列文章链接如下 TCP/IP网络编程:P1->理解网络编程和套接字 TCP/IP网络编程:P2->套接字类型 ...

  5. TCP/IP网络协议栈:ARP协议详解

    <TCP/IP网络协议栈:以太网数据包结构.802.3> <TCP/IP网络协议栈:ARP协议详解> <TCP / IP攻击:ARP缓存中毒的基本原理.TCP序列号预测和 ...

  6. 简单自定义协议的封包和解包

    简单自定义协议的封包和解包 一.通信协议 1 百度百科的解释 2 过于简单的通信协议引发的问题 3 通信协议常见内容 1.帧头 2.设备地址/类型 3.命令/指令 4.命令类型/功能码 5.数据长度 ...

  7. TCP/IP网络编程之基于TCP的服务端/客户端(二)

    回声客户端问题 上一章TCP/IP网络编程之基于TCP的服务端/客户端(一)中,我们解释了回声客户端所存在的问题,那么单单是客户端的问题,服务端没有任何问题?是的,服务端没有问题,现在先让我们回顾下服 ...

  8. TCP/IP网络协议栈面试经典题目

    目录 面试官:看你简历说精通TCP和IP,那我们来讨论下网络模型和TCP.IP协议,讲下你的理解先 面试官:看你画的图,TCP有自己的首部结构,这都有哪些字段,最好说说它们的作用 面试官:那TCP和U ...

  9. TCP/IP网络协议栈:IP协议

    <TCP/IP网络协议栈:以太网数据包结构.802.3> <TCP/IP网络协议栈:ARP协议详解> <TCP / IP攻击:ARP缓存中毒的基本原理.TCP序列号预测和 ...

最新文章

  1. 玩转用例设计:XMind2TestCase一个高效的测试用例设计解决方案
  2. 一个97年的IT人创业历程中的总结和感悟
  3. Apache PDFBox 存在高危 XXE 漏洞,建议升级至 2.0.15
  4. QML基础类型之list
  5. linux上设置git高亮
  6. linux内核模块和功能,我可以用模块替换Linux内核功能吗?
  7. Mac苹果Time Machine 备份速度太慢的解决方法!
  8. ASCALL码对照表
  9. android 截屏 简书,Android基础 截屏ScreenCapture
  10. CISCO技术(1.7万)
  11. 切换电脑窗口的快捷键
  12. 数据库可靠性/可用性、稳定性RTO/RPO
  13. 使用GCD 转自 Posted by 唐巧
  14. ASRT中文语音识别系统
  15. idea的注释老是从行首开始
  16. linux IRQ Management(六)- DTS及调试
  17. No outgoing sequence flow of the exclusive gateway ‘XXX‘ could be selected for continuing the proces
  18. 基于汽车CAN总线专有协议OBD接口的调试方法及经验
  19. Adaptive Clustering-based Malicious TrafficClassification at the Network Edge论文阅读笔记
  20. J-LINK直接烧录.bin文件到开发板

热门文章

  1. 实验23:测试泛型依赖注入★
  2. 实验15:通过注解分别创建Dao、Service、Controller★
  3. 解决oracle主键问题,解决renren-security使用oracle主键问题
  4. pandas将Series变成键值对
  5. 11.2运行异常和编译异常
  6. 四边形可以分为几类_学习知识:四边形有几种类型
  7. 写爬虫,不会正则怎么行?
  8. vue工程本地代码请求http发生跨域提示错误解决方法
  9. 怎么把本地的项目同时提交到两个仓库
  10. 网站使用QQ登录问题小结