/*************************************
文件名: server.c
TCP 组包和拆包实现算法
*/
#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;
}
代码笔记 | TCP 组包和拆包算法
最新推荐文章于 2024-04-28 19:32:02 发布