php把语音转成帧,[转载]用TCP/IP实现自己简单的应用程序协议:成帧器部分

在前面《字节和字符,对信息进行编码》,《Socket=>流,TCP连接,TCP可靠性概述》一系列的随笔中我们已经表述了相应的理论知识,现在可以动手实现一个自己的应用程序协议。

将 数据转换成在线路上传输的字节序列只完成了一半的工作,在接收端还必须将接受到的字节序列还原成原始信息。如果以流作为传输的形式,那么首先面临的问题就 是在接收端如何确定这是一条消息,换句话说就是如何定位一条消息的开始和结束。值得注意的是,这个工作应该是在应用程序协议这一层来完成而不是在TCP这 一层来完成,应用程序协议必须指定消息的接受者如何确定何时消息已完整接收。

TCP协议中没有消息边界的概念,这会让我们在解析信息的时候产生一些问题。

如果接收者试图从套接字中读取比消息本身更多的字节,将可能发生以下两种情况:

1.如果信道中没有其他消息,接收者将阻塞等待,同时无法处理接收到的消息;如果发送者也在等待接收端的响应消息,那么就会造成“死锁”

2.如果信道中还有其他消息,则接收者会将后一条的消息的一部分甚至全部读取到第一条消息中,这将会产生一些“协议错误”

因此,在时候流TCP套接字的时候,成帧就是一个非常重要的考虑因素。

对于成帧,主要有两个技术能使接收者能够准确地找到消息的结束位置:

1.消息的结束由一个特殊的标记指明,比如把一个特殊的字节序列0001等显式添加到一个消息的结束位置。这里的限制就在于传输的内容中不能包含和该特殊字节序列中一样的字符。就像HTML中符号不能直接包含在输出中,这时需要转义。

2.显式的告知长度。

在变长字段或消息前面附加一个固定的字段,用来表示该字段或者消息中包含了多少个字节。

我们来写一个网络上常见的投票来作为例子:

这个例子包含了两种类型的请求,一种是“查询”的请求,也就是查询当前的候选人获得的选票情况。

第二种是“投票”请求,服务器保存此次投票信息,并返回投完票后该候选人获得的结果。

在实现一个协议的时候,定义一个专门的类来存放消息中所包含的信息是大有裨益的。类提供了给我们封装的能力,通过属性来公开类中的可变字段,也可以维护一些不变的字段。

我在这里采用的发送消息大小的方式来确定一条完整的消息。

项目结构和功能说明如下:

f6c1092fcbeffefd88ed00b4355c6657.png

IFramer接口的定义:

namespaceVoteForMyProtocol

{publicinterfaceIFramer

{voidframeMsg(byte[] message);byte[] nextMsg();

}

}

基于长度成帧的实现:

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Net.Sockets;usingSystem.IO;namespaceVoteForMyProtocol

{publicclassLengthFramer : IFramer {publicstaticreadonlyintMAXMESSAGELENGTH=65535;

Socket s=null;publicLengthFramer(Socket s)

{this.s=s;

}//把消息成帧并发送publicvoidframeMsg(byte[] message){if(message.Length>MAXMESSAGELENGTH) {thrownewIOException ("message too long");

}inttotalSent=0;intdataLeft=message.Length;//剩余的消息intthisTimeSent;//保存消息长度byte[] datasize=newbyte[4];

datasize=BitConverter.GetBytes(message.Length);//将消息长度发送出去thisTimeSent=s.Send(datasize);//发送消息剩余的部分while(totalSent

{

thisTimeSent=s.Send(message, totalSent, dataLeft, SocketFlags.None);

totalSent+=thisTimeSent;

dataLeft-=thisTimeSent;

}

}//按帧来解析消息publicbyte[] nextMsg(){if(s==null)thrownewArgumentNullException("socket null");inttotal=0;//已接收的字节数intrecv;//接收4个字节,得到“消息长度”byte[] datasize=newbyte[4];//如果当前使用的是面向连接的 Socket,则 Receive 方法将读取所有可用的数据,直到达到 size 参数指定的字节数。//如果远程主机使用 Shutdown 方法关闭了 Socket 连接,并且所有可用数据均已收到,则 Receive 方法将立即完成并返回零字节。recv=s.Receive(datasize,0,4,0);if(recv<4)returnnull;intsize=BitConverter.ToInt32(datasize,0);//按消息长度接收数据intdataleft=size;//容器装满了就证明收集到了一条完整的消息。byte[] data=newbyte[size];//直到容器填满再返回while(total

{

recv=s.Receive(data, total, dataleft,0);

total+=recv;

dataleft-=recv;if(dataleft==0)

{break;

}

}returndata;

}

}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/452651.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实体联系图简介

通常&#xff0c;使用实体联系图(entity relationship diagram)来建立数据模型。可以把实体联系图简称为ER图&#xff0c;相应地可把用ER图描绘的数据模型称为ER模型。 ER图中包含了实体(即数据对象)、关系和属性3种基本成分&#xff0c;通常用矩形框代表实体&#xff0c;用连…

Flask爱家租房--城区信息

0.效果展示 城市列表使用缓存的过程 1.后端代码 # coding:utf-8from . import api from flask import g, current_app, jsonify, request, session from ihome.utils.response_code import RET from ihome.models import Area, House, Facility, HouseImage, User, Order from …

数值计算算法-多项式插值算法的实现与分析

数值计算是指在数值分析领域中的算法。数值分析是专门研究和数字以及近似值相关的数据问题&#xff0c;数值计算在数值分析的研究中发挥了特别重要的作用。 多项式插值是计算函数近似值的一种方法。其中函数值仅在几个点上已知。 该算法的基础是建立级数小于等于n的一个插值多项…

Linux中断 - tasklet

一、前言 对于中断处理而言&#xff0c;linux将其分成了两个部分&#xff0c;一个叫做中断handler&#xff08;top half&#xff09;&#xff0c;属于不那么紧急需要处理的事情被推迟执行&#xff0c;我们称之deferable task&#xff0c;或者叫做bottom half&#xff0c;。具体…

数字电视制播设备间的文件交换格式

在现今的数字电视演播室中&#xff0c;设备之间基本上采用信号流连接方式&#xff0c;如SDI、STDI、模拟YUV、VBS等信号流。在非线性编辑系统和播出系统与服务器之间的连接&#xff0c;还有基于MPEG-2传输流等的信号连接方式。基于信号流连接方式的主要特点是&#xff0c;传送时…

oracle 位移运算符,Oracle“(+)”运算符

在Oracle中&#xff0c;()表示JOIN中的“可选”表。 所以在你的查询中&#xff0c;select a.id, b.id, a.col_2, b.col_2, ... from a,b where a.idb.id()这是一个左外加B表与一个表。 就像现代的左连接查询一样。 (它将返回a表的所有数据&#xff0c;而不会丢失在另一边的数据…

什么是实体-联系图(ER图)

实体-联系图&#xff08;ER图&#xff09;数据模型中包含3种相互关联的信息&#xff1a;数据对象、数据对象的属性及数据对象彼此间相互连接的关系。 1.数据对象 数据对象是对软件必须理解的复合信息的抽象。所谓符合信息是指具有一系列不同性质或属性的事物&#xff0c;仅有单…

记录的习惯

记录的习惯 书籍是人类进步的阶梯&#xff0c;承载了人类文明进步的历程。大多数人都写过日记&#xff0c;但不知道有多少人重视过日记。常常我们会用相机记录一些生活中的场景&#xff0c;然后收藏起来&#xff0c;等到若干年后再拿出来看&#xff0c;总能感觉到很温馨很美好。…

Flask爱家租房--发布新房源(保存房屋基本信息)

0.页面展示效果 1.后端代码 api.route("/houses/info", methods["POST"]) login_required def save_house_info():"""保存房屋的基本信息前端发送过来的json数据{"title":"","price":"","ar…

【c#】RabbitMQ学习文档(一)Hello World

一、简介 RabbitMQ是一个消息的代理器&#xff0c;用于接收和发送消息&#xff0c;你可以这样想&#xff0c;他就是一个邮局&#xff0c;当您把需要寄送的邮件投递到邮筒之时&#xff0c;你可以确定的是邮递员先生肯定会把邮件发送到需要接收邮件的人的手里&#xff0c;不…

oracle中如何分页,Oracle中操作分页

mysql中分页的写法&#xff1a;select t.* from tbl_user t order by t.id limit $offset , $perpage$currentPage 1;//当前页码其中后面$sql&#xff1a;with partdata as (select rownum rowno,t.* from tablename t where column1090order by column) select * from partda…

Flask爱家租房--发布新房源(保存房屋图片)

0.页面展示效果 1&#xff09;首先房东填写房屋信息&#xff1b; 2&#xff09;当房东填写发布的房源信息之后&#xff0c;隐藏&#xff08;hide&#xff09;刚才填写信息的界面&#xff0c;同时显示(show)上传房屋图片的界面。 1.后端代码 api.route("/houses/image&q…

数字的处理 :小数点四舍五入

js取float型小数点后两位数的方法 转载 发布时间&#xff1a;2014年01月18日 17:03:32 投稿&#xff1a;shangke 我要评论 js中取小数点后两位方法最常用的就是四舍五入函数了&#xff0c;前面我介绍过js中四舍五入一此常用函数&#xff0c;这里正好用上&#xff0c;下面…

如何成为一名优秀的C程序员

问题的提出 每过一段时间我总会收到一些程序员发来的电子邮件&#xff0c;他们会问我是用什么编程语言来编写自己的游戏的&#xff0c;以及我是如何学习这种编程语言的。因此&#xff0c;我认为在这篇博文里列出一些有关C语言的最佳读物应该能帮到不少人。如果你知道其它的优秀…

CFS调度器

一、前言 随着内核版本的演进&#xff0c;其源代码的膨胀速度也在递增&#xff0c;这让Linux的学习曲线变得越来越陡峭了。这对初识内核的同学而言当然不是什么好事情&#xff0c;满腔热情很容易被当头浇灭。我有一个循序渐进的方法&#xff0c;那就是先不要看最新的内核&#…

Flask爱家租房--发布新房源(总结)

重点总结 学习过程中&#xff0c;发现house_id贯穿两个接口内容&#xff0c;现对后端逻辑部分做以下总结&#xff1a; 1&#xff09;房东首先在前端填写房屋的基本信息&#xff0c;此时通过newhouse.js文件$("#form-house-info").submit(function (e) {…}进行处理&…

关系代数

关系代数是一种抽象的查询语言&#xff0c;它用对关系的运算来表达查询关系代数运算对象是关系运算结果亦为关系关系代数的运算符有两类&#xff1a;集合运算符和专门的关系运算符

设计模式的六大原则

设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更加容易被他人理解、保证代码可靠性。设计模式是代码编制真正工程化&#xff08;工程化即系统化、模块化、规范化的一个过程。指将具有一定规模数量的单个…