zoukankan      html  css  js  c++  java
  • 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 !
    ");
        sfp = socket(AF_INET, SOCK_STREAM, 0);
        if(-1 == sfp)
        {
            printf("socket fail ! 
    ");
            return -1;
        }
        printf("socket ok !
    ");
        /* 填充服务器端口地址信息,以便下面使用此地址和端口监听 */
        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 !
    ");
            return -1;
        }
        printf("bind ok !
    ");
        /* 开始监听相应的端口 */
        if(-1 == listen(sfp,5))
        {
            printf("listen fail !
    ");
            return -1;
        }
        printf("listen ok
    ");
        //  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 !
    ");
                return -1;
            }
            printf("accept ok!
    Server start get connect from %#x : %#x
    ",ntohl(c_add.sin_addr.s_addr),ntohs(c_add.sin_port));
            /* 这里使用write向客户端发送信息,也可以尝试使用其他函数实现 */
            if(-1 == write(nfp,"hello,welcome to my server 
    ",32))
            {
                printf("write fail!
    ");
                return -1;
            }
     
     
    //头0xF9   两个长度字节   数据   尾0xF8
            while(1)
            {
    #ifdef TCP_PACK_DEBUG
                {
                    printf("bufSize = %d ,nBufuseLen = %d
    ",bufSize,nBufuseLen);
                }
    #endif
                if(bufSize>nBufuseLen)
                {
                    nRevOnceLen=read(nfp,buf+nBufuseLen,bufSize-nBufuseLen);
                    nBufuseLen=nBufuseLen+nRevOnceLen;
     
     
    #ifdef TCP_PACK_DEBUG
                    {
                        printf("nBufuseLen = %d>3
    ",nBufuseLen);
                    }
    #endif
                    /*
                                    printf(" nRevOnceLen data:
    ");
                                    for(i=0; i<nRevOnceLen; i++)
                                    {
                                        printf(" 0x%x ",buf[i]&0xFF);
                                    }
                                    printf(" 
    ");
                    */
     
     
                }
                else
                {
                    printf("buf if full
    ");
                }
     
     
     
     
                while(nBufuseLen>3)            //用到的大于3个字节
                {
     
     
                    /*            printf(" nBufuseLen data:
    ");
                                for(i=0; i<nBufuseLen; i++)
                                {
                                    printf(" 0x%x ",buf[i]&0xFF);
                                }
                                printf(" 
    ");
                    */
     
    #ifdef TCP_PACK_DEBUG
                    {
                        printf("buf[0] = 0x%x 
    ",buf[0]&0xFF);
                    }
    #endif
                    if((buf[0]&0xFF)==0xF9)         //
                    {
                        nPackLen=(buf[1]*256)+buf[2];
     
     
    #ifdef TCP_PACK_DEBUG
                        {
                            printf("nBufuseLen=%d ,nPackLen=%d
    ",nBufuseLen,nPackLen);
                        }
    #endif
     
     
                        if(nBufuseLen>=nPackLen)                //大于和=
                        {
    #ifdef TCP_PACK_DEBUG
                            {
                                printf("buf[nPackLen-1] = 0x%x 
    ",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 
    ", 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)
    ",nPackLen,(buf[nPackLen-1]!=0xF8));        //这里应该不会执行
                                for(i=0; i<5; i++)
                                {
                                    printf(" 0x%x ",buf[i]&0xFF);
                                }
                                printf(" 
    ");
    #endif
                                printf(" (buf[nPackLen-1]&0xFF)!=0xF8 
    ");
                                nBufuseLen=0;           //清除错误的包   //这里应该不会执行
     
     
     
     
                                break;
     
     
                            }
                        }
                        else
                        {
     
     
    #ifdef TCP_PACK_DEBUG
                            printf(" nBufuseLen<=nPackLen
    ");
    #endif
                            break;
                        }
                    }
                    else
                    {
                        printf(" (buf[0]!=0xF9)
    ");        //这里应该不会执行
                        nBufuseLen=0;           //清除错误的包   //这里应该不会执行
                        break;
                    }
                }
     
     
                /*
                            if((0xFF&buf[0])!=0xF2)
                            {
                                printf("readlen = %d buf  0x%x  0x%x  0x%x 
    ",readlen,0xFF&buf[0],0xFF&buf[1],0xFF&buf[2]);
                            }
     
     
     
     
                            if(readlen!=1027)
                                printf("readlen = %d buf  0x%x  0x%x  0x%x 
    ",readlen,0xFF&buf[0],0xFF&buf[1],0xFF&buf[2]);
     
     
                */
            }
            //  close(nfp);
        }
        // close(sfp);
        return 0;
    }
  • 相关阅读:
    disruptor笔记之一:快速入门
    React-高阶函数_函数柯里化
    解决跨域、同源策略-React中代理的配置
    React中key的作用
    React三种路由参数传递方式
    React生命周期(好玩的讲解方式)
    React数据共享插件-PubSub
    React中路由基本&高级使用
    React中嵌套路由
    React中网络请求(axios和fetch)
  • 原文地址:https://www.cnblogs.com/AquaGot/p/7242257.html
Copyright © 2011-2022 走看看