TCP 組包和拆包算法


/*************************************
文件名: server.c
TCP 組包和拆包實現算法
 
 
作者:   馬中海
QQ:     284358503
Email: zhonghaima001@163.com
*/
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <string.h>
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
 
 
#define BUF_SIZE 1024*5
 
 
//#define TCP_PACK_DEBUG 1
 
 
int main()
{
 
    int nBufuseLen=0;       //緩沖區里用到的長度
    int nRevOnceLen=0;      //read 一次讀到的長度
    int nPackLen=0;         //每一包的長度,包括頭和兩個長度和尾字節
    int bufSize=BUF_SIZE;
 
 
    unsigned char buf[BUF_SIZE];     //read 的緩存
 
 
    int i=0;
 
 
    int sfp,nfp; /* 定義兩個描述符 */
    struct sockaddr_in s_add,c_add;
    int sin_size;
    unsigned short portnum=6000; /* 服務端使用端口 */
    printf("Hello,welcome to my server !\r\n");
    sfp = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == sfp)
    {
        printf("socket fail ! \r\n");
        return -1;
    }
    printf("socket ok !\r\n");
    /* 填充服務器端口地址信息,以便下面使用此地址和端口監聽 */
    bzero(&s_add,sizeof(struct sockaddr_in));
    s_add.sin_family=AF_INET;
    s_add.sin_addr.s_addr=htonl(INADDR_ANY); /* 這里地址使用全0,即所有 */
    s_add.sin_port=htons(portnum);
    /* 使用bind進行綁定端口 */
    if(-1 == bind(sfp,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
    {
        printf("bind fail !\r\n");
        return -1;
    }
    printf("bind ok !\r\n");
    /* 開始監聽相應的端口 */
    if(-1 == listen(sfp,5))
    {
        printf("listen fail !\r\n");
        return -1;
    }
    printf("listen ok\r\n");
    //  while(1)
    {
 
 
        //    char buf[1027];
        //    int readlen;
 
 
        sin_size = sizeof(struct sockaddr_in);
        /* accept服務端使用函數,調用時即進入阻塞狀態,等待用戶進行連接,在沒有客戶端進行連接時,程序停止在此處,
           不會看到后面的打印,當有客戶端進行連接時,程序馬上執行一次,然后再次循環到此處繼續等待。
           此處accept的第二個參數用於獲取客戶端的端口和地址信息。
            */
        nfp = accept(sfp, (struct sockaddr *)(&c_add), &sin_size);
        if(-1 == nfp)
        {
            printf("accept fail !\r\n");
            return -1;
        }
        printf("accept ok!\r\nServer start get connect from %#x : %#x\r\n",ntohl(c_add.sin_addr.s_addr),ntohs(c_add.sin_port));
        /* 這里使用write向客戶端發送信息,也可以嘗試使用其他函數實現 */
        if(-1 == write(nfp,"hello,welcome to my server \r\n",32))
        {
            printf("write fail!\r\n");
            return -1;
        }
 
 
//頭0xF9   兩個長度字節   數據   尾0xF8
        while(1)
        {
#ifdef TCP_PACK_DEBUG
            {
                printf("bufSize = %d ,nBufuseLen = %d\n",bufSize,nBufuseLen);
            }
#endif
            if(bufSize>nBufuseLen)
            {
                nRevOnceLen=read(nfp,buf+nBufuseLen,bufSize-nBufuseLen);
                nBufuseLen=nBufuseLen+nRevOnceLen;
 
 
#ifdef TCP_PACK_DEBUG
                {
                    printf("nBufuseLen = %d>3\n",nBufuseLen);
                }
#endif
                /*
                                printf(" nRevOnceLen data:\n");
                                for(i=0; i<nRevOnceLen; i++)
                                {
                                    printf(" 0x%x ",buf[i]&0xFF);
                                }
                                printf(" \n");
                */
 
 
            }
            else
            {
                printf("buf if full\n");
            }
 
 
 
 
            while(nBufuseLen>3)            //用到的大於3個字節
            {
 
 
                /*            printf(" nBufuseLen data:\n");
                            for(i=0; i<nBufuseLen; i++)
                            {
                                printf(" 0x%x ",buf[i]&0xFF);
                            }
                            printf(" \n");
                */
 
#ifdef TCP_PACK_DEBUG
                {
                    printf("buf[0] = 0x%x \n",buf[0]&0xFF);
                }
#endif
                if((buf[0]&0xFF)==0xF9)         //
                {
                    nPackLen=(buf[1]*256)+buf[2];
 
 
#ifdef TCP_PACK_DEBUG
                    {
                        printf("nBufuseLen=%d ,nPackLen=%d\n",nBufuseLen,nPackLen);
                    }
#endif
 
 
                    if(nBufuseLen>=nPackLen)                //大於和=
                    {
#ifdef TCP_PACK_DEBUG
                        {
                            printf("buf[nPackLen-1] = 0x%x \n",buf[nPackLen-1]&0xFF);
                        }
#endif
 
 
                        if((buf[nPackLen-1]&0xFF)==0xF8)                  //
                        {
                            //找到一包數據,所有的數據都往前移動nPackLen個字節
#ifdef TCP_PACK_DEBUG
                            {
                                printf("head 0x%x length %d tail 0x%x \n", buf[0]&0xFF,nPackLen,buf[nPackLen-1]&0xFF);
                            }
#endif
 
 
                            for(i=0; i<nBufuseLen-nPackLen; i++)
                            {
                                buf[i]=buf[nPackLen+i];
                            }
 
 
                            nBufuseLen=nBufuseLen-nPackLen;      //用到的字節變小了
                            //   continue;           //不要read了
                        }
                        else
                        {
 
 
#ifdef TCP_PACK_DEBUG
                            printf("buf[%d-1]=0x%x,(buf[0]!=0xF8)\n",nPackLen,(buf[nPackLen-1]!=0xF8));        //這里應該不會執行
                            for(i=0; i<5; i++)
                            {
                                printf(" 0x%x ",buf[i]&0xFF);
                            }
                            printf(" \n");
#endif
                            printf(" (buf[nPackLen-1]&0xFF)!=0xF8 \n");
                            nBufuseLen=0;           //清除錯誤的包   //這里應該不會執行
 
 
 
 
                            break;
 
 
                        }
                    }
                    else
                    {
 
 
#ifdef TCP_PACK_DEBUG
                        printf(" nBufuseLen<=nPackLen\n");
#endif
                        break;
                    }
                }
                else
                {
                    printf(" (buf[0]!=0xF9)\n");        //這里應該不會執行
                    nBufuseLen=0;           //清除錯誤的包   //這里應該不會執行
                    break;
                }
            }
 
 
            /*
                        if((0xFF&buf[0])!=0xF2)
                        {
                            printf("readlen = %d buf  0x%x  0x%x  0x%x \n",readlen,0xFF&buf[0],0xFF&buf[1],0xFF&buf[2]);
                        }
 
 
 
 
                        if(readlen!=1027)
                            printf("readlen = %d buf  0x%x  0x%x  0x%x \n",readlen,0xFF&buf[0],0xFF&buf[1],0xFF&buf[2]);
 
 
            */
        }
        //  close(nfp);
    }
    // close(sfp);
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM