- 浏览: 528550 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
c7887qin:
貌似还要使用相同的证书进行签名。。。
Android - 如何将两个/多个应用放到一个进程中去? -
北极光之吻:
天天向上1989 写道不是有OnDoubleTapListen ...
android实现双击事件监听 -
nielong123:
nielong123 写道onCheckedChanged(M ...
Android RadioGroup 换行, 支持多行多列 -
nielong123:
onCheckedChanged(MultiRadioGrou ...
Android RadioGroup 换行, 支持多行多列 -
zk_Ming:
zk_Ming 写道我用了你的,但是radiogroup 点击 ...
Android RadioGroup 换行, 支持多行多列
1 场景
当用socket进行进程通信,传输数据的时候,会出现以下一些情况:
(1)完整的一条消息被系统拆分成几条发送,例如要发送一条消息:Hello World ,却被系统分成两条消息发送,分别为:Hello 和 World。
(2)几条独立的消息被系统合成一条消息发送,例如要发送两条消息分别为:a memory from my past和it’s been a year,却被系统和成一条消息发送:a memory from my pastit’s been a year。
这个时候,需要为socket通信设计一种通信协议,以保证数据的准确性。
2 协议格式
通信协议设计如下:
Head:帧头,2个字节,此处为0xa5a5
Type:通信类型,1个字节,范围0x00~0xff
Data Length:数据长度,1个字节,即Data的字节总数,
Data:实际传输的数据,长度不定
CS:校验值,1个字节,type、data length、data三个域所有字节的异或值,实际中并没用到校验
End:帧尾,2个字节,此处为0xbeef
3 程序设计
3.1 解析思路
假设socket客户端C和服务端S通信,C向S发送消息M1。
1、 S收到消息M1。S把消息M1拷贝到缓存Q中,Q为循环队列。假如M1的长度大于Q的剩余空间,则只拷贝剩余空间大小的字节到Q。
2、 从Q的当前指针开始,查找帧头<Head>。如果找到,则当前指针向后移2个字节位置,继续查找<Type>;如果没找到,则删除前1个字节,当前指针向后移1个字节位置,继续查找<Head>
3、 从Q的当前指针开始,查找<Type>。如果Q中至少还剩一个字节,则表示找到,当前指针向后移1个字节位置,否则退出解析。
4、 从Q的当前指针开始,查找<DataLength>。如果Q中至少还剩一个字节,则表示找到,当前指针向后移1个字节位置,否则退出解析。
5、 从Q的当前指针开始,向后移DataLength个字节位置,查找<End>。如果找到,则从Q中取出一条完整的消息P1,并从Q中删除此消息空间,调用外部的回调函数;否则删除帧头的第一个字节a5,当前指针指向帧头第二个字节a5位置,从步骤2开始,重新一轮解析。
3.2 数据结构
查找策略枚举,用于查找时判断查找帧结构的哪个部位:
消息结构体,用于存储从缓存中解析出的数据:
回调函数,用于从缓存中解析出消息时调用:
循环队列,用于缓存接收到的数据:
3.3 关键实现
1、把接收到的数据存储到缓冲中,并准备解析:
2、递归解析消息:
当用socket进行进程通信,传输数据的时候,会出现以下一些情况:
(1)完整的一条消息被系统拆分成几条发送,例如要发送一条消息:Hello World ,却被系统分成两条消息发送,分别为:Hello 和 World。
(2)几条独立的消息被系统合成一条消息发送,例如要发送两条消息分别为:a memory from my past和it’s been a year,却被系统和成一条消息发送:a memory from my pastit’s been a year。
这个时候,需要为socket通信设计一种通信协议,以保证数据的准确性。
2 协议格式
通信协议设计如下:
Head:帧头,2个字节,此处为0xa5a5
Type:通信类型,1个字节,范围0x00~0xff
Data Length:数据长度,1个字节,即Data的字节总数,
Data:实际传输的数据,长度不定
CS:校验值,1个字节,type、data length、data三个域所有字节的异或值,实际中并没用到校验
End:帧尾,2个字节,此处为0xbeef
3 程序设计
3.1 解析思路
假设socket客户端C和服务端S通信,C向S发送消息M1。
1、 S收到消息M1。S把消息M1拷贝到缓存Q中,Q为循环队列。假如M1的长度大于Q的剩余空间,则只拷贝剩余空间大小的字节到Q。
2、 从Q的当前指针开始,查找帧头<Head>。如果找到,则当前指针向后移2个字节位置,继续查找<Type>;如果没找到,则删除前1个字节,当前指针向后移1个字节位置,继续查找<Head>
3、 从Q的当前指针开始,查找<Type>。如果Q中至少还剩一个字节,则表示找到,当前指针向后移1个字节位置,否则退出解析。
4、 从Q的当前指针开始,查找<DataLength>。如果Q中至少还剩一个字节,则表示找到,当前指针向后移1个字节位置,否则退出解析。
5、 从Q的当前指针开始,向后移DataLength个字节位置,查找<End>。如果找到,则从Q中取出一条完整的消息P1,并从Q中删除此消息空间,调用外部的回调函数;否则删除帧头的第一个字节a5,当前指针指向帧头第二个字节a5位置,从步骤2开始,重新一轮解析。
3.2 数据结构
查找策略枚举,用于查找时判断查找帧结构的哪个部位:
typedef enum{ SEARCH_HEAD, SEARCH_TYPE, SEARCH_LEN, //SEARCH_CS, SEARCH_END, SEARCH_NONE }cache_strategy;
消息结构体,用于存储从缓存中解析出的数据:
typedef struct{ unsigned char data[SOCKET_MSG_SIZE]; //data int len; unsigned char type; }socket_msg;
回调函数,用于从缓存中解析出消息时调用:
typedef void (*tp_socket_msg_handle)(int fd, socket_msg *msg,void *args);
循环队列,用于缓存接收到的数据:
typedef struct{ unsigned char buf[SOCKET_MSG_CACHE_SIZE]; //buffer for storing data read from client int front; int rear; int current; int len; int tag; //mark that whether the cache is full,1-full,0-not full cache_strategy strategy; tp_socket_msg_handle handle;//callback function to invoke when a message is parsed out void* args; //external parameter socket_msg recv_msg; //parsed message }socket_cache;
3.3 关键实现
1、把接收到的数据存储到缓冲中,并准备解析:
//copy the unparsed data to cache, and parsed them int socket_msg_pre_parse( int fd, socket_cache *cache, unsigned char *buf, int len, void *args) { int n = 0; unsigned char *p = buf; //when reading buffer's length is greater than cache's left length, //we should copy many times. cache->args = args; while(1){ n = socket_msg_cpy_in(cache, p, len); if(n == 0){ return FALSE;//cache is full } //parse and handle socket message from cache socket_msg_parse(fd, cache); if(n == len){ return TRUE; //copy completed } //move the pointer p = p + n; len = len - n; } return TRUE; }
2、递归解析消息:
//parsed the packaged data, and invoke callback function void socket_msg_parse(int fd, socket_cache *cache) { int current_len; int p, q; int i; int find; if(cache->front == cache->rear && cache->tag == 0){ //D("socket cache is empty!\n"); return; } //calculate the current length of cache if(cache->current >= cache->front){ current_len = cache->len - (cache->current - cache->front); } else{ current_len = cache->rear - cache->current; } switch(cache->strategy){ case SEARCH_HEAD://to find a Head format in cache if(current_len < SOCKET_MSG_HEAD_SIZE){ return; } find = FALSE; for(i = 0; i < current_len - 1; i++){ p = cache->current; q = (cache->current + 1) % SOCKET_MSG_CACHE_SIZE; if( (cache->buf[p] == (SOCKET_MSG_HEAD >> 8))&& (cache->buf[q] == (SOCKET_MSG_HEAD & 0xff))){ find = TRUE; break; //exit for loop } else{ //current pointer move to next cache->current = q; //delete one item cache->front = cache->current; cache->len --; cache->tag = 0; } } if(find == TRUE){ //move 2 items towards next cache->current = (cache->current + 2) % SOCKET_MSG_CACHE_SIZE; //we found the head format, go on to find Type byte cache->strategy = SEARCH_TYPE; } else{ //if there is no head format ,delete previouse items LOGE("socket message without head: %x!\n",SOCKET_MSG_HEAD); //go on to find Head format cache->strategy = SEARCH_HEAD; } break; case SEARCH_TYPE://to find the type byte in cache if(current_len < SOCKET_MSG_TYPE_SIZE){ return ; } //get the value of type //cache->type = cache->buf[cache->current]; cache->recv_msg.type = cache->buf[cache->current]; cache->current = (cache->current + 1) % SOCKET_MSG_CACHE_SIZE; //we found Type byte, go on to find Datalen format cache->strategy = SEARCH_LEN; break; case SEARCH_LEN://to find the datalen byte in cache if(current_len < SOCKET_MSG_LEN_SIZE){ return ; } if(cache->buf[cache->current] > SOCKET_MSG_DATA_SIZE){ LOGE("the data len of message out of size: %d!\n",SOCKET_MSG_DATA_SIZE); //delete the frist item 'a5' //move back 2 items cache->current = cache->current >= 2 ? (cache->current - 2) : (SOCKET_MSG_CACHE_SIZE - 2 + cache->current); cache->front = cache->current; //length sub 2 cache->len -= 2; cache->tag = 0; //go on to find Head format cache->strategy = SEARCH_HEAD; } else{ //get the value of datalen //cache->data_len = cache->buf[cache->current]; cache->recv_msg.len = cache->buf[cache->current]; cache->current = (cache->current + 1) % SOCKET_MSG_CACHE_SIZE; //we found datalen byte, go on to find End format cache->strategy = SEARCH_END; } break; case SEARCH_END: if(current_len < (cache->recv_msg.len + SOCKET_MSG_END_SIZE)){ return; } //because we have known the data bytes' len, so we move the very //distance of datalen to see if there is End format. p = (cache->current + cache->recv_msg.len) % SOCKET_MSG_CACHE_SIZE; q = (cache->current + cache->recv_msg.len + 1) % SOCKET_MSG_CACHE_SIZE; if( (cache->buf[p] == (SOCKET_MSG_END >> 8))&& (cache->buf[q] == (SOCKET_MSG_END & 0xff)) ){ socket_msg_cpy_out(cache, cache->recv_msg.data, cache->current, cache->recv_msg.len); if(cache->handle != NULL){ //cache->handle(fd, cache->buf + cache->data_index, cache->data_len); cache->handle(fd, &cache->recv_msg, cache->args); } //delete all previous items cache->current = (q + 1) % SOCKET_MSG_CACHE_SIZE; cache->front = cache->current; cache->len -= (cache->recv_msg.len + SOCKET_MSG_FORMAT_SIZE); cache->tag =0; } else{ LOGE("socket message without end: %x!\n",SOCKET_MSG_END); //delete the frist item 'a5' //move back 3 items cache->current = cache->current >= 3 ? (cache->current - 3) : (SOCKET_MSG_CACHE_SIZE - 3 + cache->current); cache->front = cache->current; //length sub 3 cache->len -= 3; cache->tag = 0; } //go on to find Head format cache->strategy = SEARCH_HEAD; break; default: break; } //parse new socket message socket_msg_parse(fd,cache); }
发表评论
-
正则表达式大全
2014-03-18 17:05 1019正则表达式匹配网址: (https://[\w]*.|http ... -
正则表达式大全
2014-03-18 16:53 0正则表达式匹配网址: (https://[\w]*.|http ... -
jni jstring 、char* 类型的转换
2014-03-06 18:20 850jni jstring 、char* 类型的转换 //jst ... -
基于 Android NDK 的学习之旅-----资源释放
2014-01-11 14:37 1138转载于http://www.cnblogs.com ... -
root卸载系统程序
2013-02-20 10:31 1748大家知道,卸载程序分为两种。一种是普通的应用程序,一种 ... -
java.lang.IllegalStateException: tried to write 1544 bytes with content-length
2013-01-31 14:57 1424上传文件时,content-length定义的长度小于 ... -
C++实现员工信息管理系统
2012-11-16 18:35 1581using namespace std; #incl ... -
undefined reference socket@。。。问题解决
2012-08-27 15:51 4330Eclipse C/C++关于socket(tcp/ip)相关 ... -
Ubuntu adb devices :???????????? no permissions 解决方法
2012-04-06 16:54 1817因为ubuntu这样的系统都是默认以非root身份在运行的,要 ... -
sysv-rc-conf 设置ubuntu开机自启动
2012-03-08 15:49 3574Java代码 sudo apt-get install s ... -
Ubuntu 创建开机自启动脚本
2012-03-08 14:27 2036Ubuntu 创建开机自启动脚本的步骤如下: 1) 将你的启动 ... -
Swing界面美化
2012-02-13 18:18 9567转发自:http://blog.163.com/li_hy20 ... -
Android JNI知识简介
2011-10-20 13:47 1698Java Native Interface (JNI)标准是j ... -
一个JNI入门级教程(linux版)
2011-10-16 21:46 3677学了JAVA一段时间后,如果你意识到JAVA的瓶颈所在,那就是 ... -
解决java.lang.NoClassDefFoundError错误
2011-10-16 21:30 1887一个基础问题: package com.test; pu ... -
修改Ubuntu启动菜单使windows XP/Vista/win 7变为默认启动系统
2011-08-08 12:05 1544很多朋友在电脑上装了Windows和ubuntu双系统,电脑是 ... -
Eclipse ADT插件在ubuntu从10.04升级到10.10后失效的问题解决
2011-07-28 17:34 2235原文出处:http://sonalsantan.blogspo ... -
SDL init failure, reason is: No available video device: On Ubuntu64 .
2011-07-21 15:48 1652If you are installing Android S ... -
Android系统源码导入到eclipse
2011-07-21 11:05 74521.把eclipse工程配置文件复制到android源码根目录 ... -
JAVA执行Linux命令的方法
2011-07-20 15:59 2286/** 执行Linux命令,并返回执行结果。 ...
相关推荐
本文将深入探讨基于Linux和Unix环境的Socket编程,主要关注C语言实现,以及C++对Socket编程的封装。 首先,Socket是网络通信中的一个抽象概念,它是一个端点,用于两台计算机之间的数据交换。在Unix和Linux系统中,...
本教程主要聚焦于如何使用C语言实现基于Socket的自定义协议通信,涵盖了客户端和服务端的实现。我们将深入理解Socket编程的基本概念,学习如何创建、连接、监听Socket,并探讨如何设计和实现自定义的数据传输协议。 ...
**SIP协议解析与实现(c/c++)** SIP(Session Initiation Protocol)协议是一种用于创建、修改和终止多媒体通信会话的信令协议,广泛应用于VoIP、视频会议和即时消息等领域。根据RFC3261,SIP设计为简单、可扩展且...
本项目"基于socket的多线程聊天程序"是使用C++语言在Windows环境下,利用Microsoft Visual C++ 6.0(简称VC6.0)开发的一款群聊应用程序。下面我们将详细探讨其中涉及的关键知识点。 1. **Socket编程**:Socket是...
本资源包“C/C++基于VS开发的modbustcp源程序.rar”聚焦于C/C++编程语言,利用Visual Studio(VS)开发环境实现Modbus TCP的通信功能。这里我们将深入探讨Modbus、Modbus TCP、Socket编程以及C/C++在VS中的应用。 ...
在本文中,我们将深入探讨如何使用C++在Windows平台上实现基于TCP协议的最简单的客户端/服务器(C/S)网络通信。TCP(传输控制协议)是一种面向连接、可靠的通信协议,常用于建立稳定的数据交换通道。 首先,让我们...
通用工业协议(EtherNet/IP)是自动化领域广泛应用的一种通信标准,它基于开放的以太网技术,实现了设备间高效的数据交换。EtherNet/IP利用了通用互联网协议(TCP/IP)和实时工业以太网协议(CIP)来实现控制器对控制...
- **客户端/服务器模型**:实现简单的C/S架构程序,了解数据传输过程中的注意事项。 #### 三、并发处理技术 - **多线程编程**:使用pthread库进行多线程开发,提高程序执行效率。 - **进程间通信(IPC)**:学习...
以上就是一个简单的C/C++ socket通信的例子,适合初学者入门。在实际项目中,可能需要处理多客户端连接、错误处理、线程同步等问题,这需要更深入的学习和实践。使用VS2005这样的IDE可以方便地调试和运行代码,对于...
1. **网络通信**:C/C++中可以使用如socket库进行网络编程,实现TCP/UDP通信。客户端和服务器端通过socket建立连接,发送和接收数据。 2. **多线程/异步处理**:为了处理并发请求,网关通常需要支持多线程或多进程...
以下是一个简单的TCP socket通信示例: 1. 创建服务器端socket: ```cpp int serverSocket = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in serverAddress; serverAddress.sin_family = AF_INET; server...
本文将深入探讨基于SOCKET的C++即时通讯系统,包括其原理、实现方式以及涉及到的关键技术。 首先,SOCKET是操作系统提供的一种通信接口,允许应用程序通过TCP/IP协议进行网络通信。在C++中,利用SOCKET API可以创建...
"基于Socket的C/S通信层"是这种技术的一个实例,它利用Socket API实现客户端(Client)和服务器(Server)之间的通信。Socket是网络编程中的基本概念,它提供了进程间通信(IPC)的能力,尤其在跨网络的环境中,允许...
C++ Socket通信库是用于实现网络通信的一种工具,它基于操作系统提供的Socket接口,为开发者提供了一种在C++程序中进行网络数据交换的标准方法。Socket库简化了网络编程,允许程序员通过调用特定的API函数来创建、...
2. **TCP和UDP协议**:TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,它确保数据的正确排序和丢失重传。而UDP(用户数据报协议)则是一种无连接的、不可靠的协议,提供快速的数据传输...
在C++中实现这些协议的文件下载,通常会涉及以下关键知识点: 1. **套接字编程**:套接字是网络通信的基础,是进程间通信的一种方式。C++中可以使用标准库`<sys/socket.h>`或第三方库如libcurl来创建和管理套接字。...
在C/C++中,通过socket接口可以直接与网络通信,实现TCP/IP协议栈中的低级别操作。Socket API提供了建立连接、发送数据、接收数据以及关闭连接等功能,是编写网络应用程序的基础。 MFC是微软为Windows平台提供的一...
标题中的"CPP_simple_client_server_socket-master_c/C++_simple_"暗示了这是一个关于C++实现的简单客户端-服务器套接字程序。在这个项目中,开发者可能创建了一个基础的网络通信框架,用于演示如何在C++中使用套接...
《使用C/C++基于Socket实现的HTTP服务器详解》 在IT行业中,服务器开发是一项至关重要的技术,特别是对于互联网服务来说。本文将详细讲解如何仅使用C/C++编程语言,通过Socket API来构建一个简单的多线程HTTP服务器...
本项目聚焦于基于socket的TCP协议下client端的实现,采用C++编程语言,非常适合初学者进行网络编程的学习和实践。下面将详细阐述相关知识点。 首先,TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。它...