5. 设计应用层协议(粘包)
Posted 阿龙亡命天涯
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5. 设计应用层协议(粘包)相关的知识,希望对你有一定的参考价值。
为什么要自己设计协议?
左边是客户端 右边是服务端
服务端输出:
分开三次发送,服务端应该分开收到三次字符,但是结果是一次性收到了三个字符
分析:
发送的时候ABC按序发送、到达。
发送的数据先进入发送缓冲区,再由操作系统发送给远程主机。
接受数据时接受到的数据存入接受缓冲区,程序从缓冲区读取数据。
A B C都在接受缓冲区,所以读取的时候一次性接受。
数据接收端无法知道数据的发送方式(独立发送还是报答报送)
解决方法:自己设计协议,包含长度等信息
柔性数组在《C语言剖析》中记载过…
//message.h
#ifndef _MESSAGE_H_
#define _MESSAGE_H_
typedef struct message
unsigned short type;
unsigned short cmd;
unsigned short index;
unsigned short total;
unsigned int length;
unsigned char payload[];
Message;
Message* Message_New(unsigned short type,unsigned short cmd,
unsigned short index,unsigned total,
const char* payload,unsigned int length);
#endif
//message.c
#include "message.h"
#include <malloc.h>
#include <string.h>
Message* Message_New(unsigned short type,unsigned short cmd, unsigned short index,unsigned total,const char* payload,unsigned int length)
Message* ret = malloc(sizeof(Message) + length);
if(ret)
ret->type=type;
ret->cmd=cmd;
ret->index=index;
ret->total=total;
ret->length=length;
if(payload)
memcpy(ret+1,payload,length);
return ret;
//client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "message.h"
int main()
int sock = 0;
struct sockaddr_in addr = 0;
int len = 0;
char buf[128] = 0;
char input[32] = 0;
int r = 0;
Message* pm = NULL;
sock = socket(PF_INET, SOCK_STREAM, 0);
if( sock == -1 )
printf("socket error\\n");
return -1;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(8888);
if( connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1 )
printf("connect error\\n");
return -1;
printf("connect success\\n");
pm = Message_New(0, 0, 1, 3, "A", 1);
send(sock, pm, sizeof(Message) + 1, 0);
pm = Message_New(0, 0, 2, 3, "B", 1);
send(sock, pm, sizeof(Message) + 1, 0);
pm = Message_New(0, 0, 3, 3, "C", 1);
send(sock, pm, sizeof(Message) + 1, 0);
close(sock);
return 0;
//server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
int server = 0;
struct sockaddr_in saddr = 0;
int client = 0;
struct sockaddr_in caddr = 0;
socklen_t asize = 0;
int len = 0;
char buf[32] = 0;
int r = 0;
server = socket(PF_INET, SOCK_STREAM, 0);
if( server == -1 )
printf("server socket error\\n");
return -1;
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(8888);
if( bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1 )
printf("server bind error\\n");
return -1;
if( listen(server, 1) == -1 )
printf("server bind error\\n");
return -1;
printf("server start success\\n");
while( 1 )
asize = sizeof(caddr);
client = accept(server, (struct sockaddr*)&caddr, &asize);
if( client == -1 )
printf("client accept error\\n");
return -1;
printf("client: %d\\n", client);
do
r = recv(client, buf, sizeof(buf), 0);
if( r > 0 )
int i = 0;
for(i=0; i<r; i++)
printf("%02X ", buf[i]);
printf("\\n");
while ( r > 0 );
close(client);
close(server);
return 0;
通过眼睛解析打印输出:
前四个字节分别是type cmd,后四个字节为index total,紧接着的四个字节是长度1,之后就是数据41(a),重复三次
以上是关于5. 设计应用层协议(粘包)的主要内容,如果未能解决你的问题,请参考以下文章