8、应用层协议设计与实现
① 问题:下面的代码输出什么?为什么
Receive: ABC
② 小知识
- 发送缓冲区
- 数据先进入发送缓冲区,之后由操作系统送往远端主机
- 接收缓冲区
- 远端数据被操作系统接收后放入接收缓冲区
- 之后应用程序从接收缓冲区读取数据
③ TCP应用编程中的“问题” 数据接收端无法知道数据的发送方式!!!
④ 网络编程中的期待
- 每次发送一条完整的消息,每次接收一条完整的消息
- 即使接收缓冲区中有多条消息,也不会出现消息粘连(粘包)
- 消息中涵盖了数据类型和数据长度等信息
⑤ 应用层协议设计
- 什么是协议?
- 协议是通信双方为数据交换而建立的规则、标准或约定的集合
- 协议对数据传输的作用
- 通信双方根据协议能够正确收发数据
- 通信双方根据协议能够解释数据的意义
⑥ 协议设计示例
- 目标:设计可用于数据传输的协议
- 完整消息包含
- 数据头:数据类型(即:数据区用途,固定长度)
- 数据长度:数据区长度(固定长度)
- 数据区:字节数据(变长区域)
⑦ 协议设计示例
因此:
- 消息至少12个字节(消息头+数据长度)
- 通过计算消息的总长度,能够避开数据粘连的问题
⑧ 编程实验:应用层协议设计与实现
message.c
#include "message.h"
#include <malloc.h>
#include <string.h>
Message* Message_New(unsigned short type, unsigned short cmd, unsigned short index, unsigned short 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;
}
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 short total,
const char* payload,
unsigned int length);
#endif
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