闲着没事做,记录一下开发项目用过的协议,项目中,大多是是实时显示播放的,通过私有协议,传输到上位机,实时播放,延时小于200ms,仿照这些协议,定义的数据格式。如果用这些协议,有时延时会比较大,这些协议适合做直播,延时3s,也不会怎么样,看直播的都知道,有几秒的延时,但是实时播放,不太适合。
总结自网络,自己记的笔记
一、流媒体概述
这几年来,视频直播、游戏直播、竞赛直播等已经成为互联网行业的大热话题,本文主要和大家谈谈直播协议、视频推流等技术内容。
所谓流媒体是指采用流式传输的方式在 Internet 播放的媒体格式。流媒体又叫流式媒体,它是指把实时的视频流或音频流传送到服务器,服务器再把视频流或音频流当成数据包发出,传送到网络上。用户通过解压设备对这些数据进行解压后,节目就会像发送前那样显示和播放出来。
流式传输方式是将视频和音频等多媒体文件经过特殊的压缩方式分成一个个压缩包,由服务器向用户计算机连续、实时传送。在采用流式传输方式的系统中,用户不必像非流式播放那样等到整个文件全部下载完毕后才能看到当中的内容,而是只需要经过几秒钟或几十秒的启动延时即可在用户计算机上利用相应的播放器对压缩的视频或音频等流式媒体文件进行播放,剩余的部分将继续进行下载,直至播放完毕。
二、流媒体协议
常见的有这些协议(RTP,RTCP,RTSP,RTMP,HTTP)。这些都是应用层协议,在tcp、udp之上。实时传输协议(RTP)和实时控制协议(RTCP)
一个典型的流媒体传输过程方式如下,具体后面讲。
一个rtsp协议的客户端和服务端的方式如下。
http协议方式
有了上面的概念,再来学习它们的区别。
流媒体直播协议
1、RTP :
RTP (Real-time Transport Protocol)
RTP是用于Internet上针对多媒体数据流的一种传输层协议。结合下图看,RTP 协议和 RTP 控制协议 RTCP 一起使用,
而且它是建立在 UDP 协议上的。RTP 不像http和ftp可完整的下载整个影视文件,它是以固定的数据率在网络上发送数据,
客户端也是按照这种速度观看影视文件,当影视画面播放过后,就不可以再重复播放,除非重新向服务器端要求数据。为啥要用udp,做个音视频传输的都知道,网络不稳定时,丢了数据,也没关系,顶多画面花屏,如果用tcp重传,那就卡顿了,一直在发送几秒前的视频,没有实时性了。
2、RTCP
RTCP:Real-time Transport Control Protocol 或 RTP Control Protocol或简写 RTCP)
RTCP即实时传输控制协议,是实时传输协议(RTP)的一个姐妹协议。RTP 协议和 RTP控制协议(RTCP) 一起使用,
而且它是建立在UDP协议上的。rtcp是传输控制命令的,rtp是传输数据的。
3、RTSP
RTSP:(Real Time Streaming Protocol)
RTSP是用来控制声音或影像的多媒体串流协议,RTSP 提供了一个可扩展框架,使实时数据,如音频与视频的受控、点播成为可能。媒体数据使用rtp,rtcp协议。一般使用udp作为传输层。适合IPTV场景。数据源包括现场数据与存储在剪辑中的数据。该协议目的在于控制多个数据发送连接,为选择发送通道,如UDP、多播UDP与TCP提供途径,并为选择基于RTP上发送机制提供方法传输时所用的网络通讯协定并不在其定义的范围内,服务器端可以自行选择使用TCP或UDP来传送串流内容,比较能容忍网络延迟。rtsp用来建立连接,控制传输的。RTSP以C/S模式工作,它是一个多媒体播放控制协议,主要用来使用户在播放流媒体时可以像操作本地的影碟机一样进行控制,即可以对流媒体进行暂停/继续、后退和前进等控制
RTSP 与 RTP 最大的区别在于:RTSP 是一种双向实时数据传输协议,在播放文件非实时流时,它允许客户端向服务器端发送请求,如回放、快进、倒退等操作。当然,RTSP 可基于 RTP 来传送数据,还可以选择 TCP、UDP、组播 UDP 等通道来发送数据,具有很好的扩展性。它时一种类似与http协议的网络应用层协议。RTSP在制定时较多地参考了HTTP/1.1协议,甚至许多描述与HTTP/1.1完全相同。RTSP之所以特意使用与HTTP/1.1类似的语法和操作,在很大程度上是为了兼容现有的Web基础结构,正因如此,HTTP/1.1的扩展机制大都可以直接引入到RTSP中。
4、RTMP
RTMP(Real Time Messaging Protocol)
Macromedia 开发的一套视频直播协议,现在属于 Adobe。和 HLS 一样都可以应用于视频直播,基于TCP不会丢失。区别是 RTMP 基于 flash 无法在 iOS 的浏览器里播放,但是实时性比 HLS 要好。RTMP实时消息传送协议是 Adobe Systems 公司为 Flash 播放器和服务器之间音频、视频和数据传输 开发的开放协议。iOS 代码里面一般常用的是使用 RTMP 推流,可以使用第三方库 librtmp-iOS 进行推流,librtmp 封装了一些核心的 API 供使用者调用。
RTMP 协议也要客户端和服务器通过“握手”来建立 RTMP Connection,然后在Connection上传输控制信息。RTMP 协议传输时会对数据格式化,而实际传输的时候为了更好地实现多路复用、分包和信息的公平性,发送端会把Message划分为带有 Message ID的Chunk,每个Chunk可能是一个单独的Message,也可能是Message的一部分,在接受端会根据Chunk中包含的data的长度,message id和message的长度把chunk还原成完整的Message,从而实现信息的收发。
5、HTTP协议
HTTP的视频协议,主要是在互联网普及之后。在互联网上看视频的需求下形成的。
最初的HTTP视频协议,没有任何特别之处,就是通用的HTTP文件渐进式下载。本质就是下载视频文件,而利用视频文件本身的特点,就是存在头部信息,和部分视频帧数据,就完全可以解码播放了。显然这种方式需要将视频文件的头部信息放在文件的前面。有些例如faststart工具,就是专门做这个功能的。
但是最为原始的状态下,视频无法进行快进或者跳转播放到文件尚未被下载到的部分。这个时候对HTTP协议提出了range-request的要求。这个目前几乎所有HTTP的服务器都支持了。range-request,是请求文件的部分数据,指定偏移字节数。在视频客户端解析出视频文件的头部后,就可以判断后续视频相应的帧的位置了。或者根据码率等信息,计算相应的为位置。
优点:
HTTP Live Streaming 还有一个巨大优势:自适应码率流播(adaptive streaming)。效果就是客户端会根据网络状况自动选择不同码率的视频流,条件允许的情况下使用高码率,网络繁忙的时候使用低码率,并且自动在二者间随意切换。这对移动设备网络状况不稳定的情况下保障流畅播放非常有帮助。实现方法是服务器端提供多码率视频流,并且在列表文件中注明,播放器根据播放进度和下载速度自动调整。使用起来也非常简单。
缺点:
实时性相对较差,直播的时候延迟比较高。
6、HLS
HLS:HTTP Live Streaming(HLS)
HLS是苹果公司(Apple Inc.)实现的基于HTTP的流媒体传输协议,可实现流媒体的直播 和点播 ,主要应用在iOS系统,为iOS设备(如iPhone、iPad)提供音视频直播和点播方案。
HLS 点播,基本上就是常见的分段HTTP点播,不同在于,它的分段非常小。相对于常见的流媒体直播协议,例如RTMP协议、RTSP 协议、MMS 协议等,HLS 直播最大的不同在于,直播客户端获取到的,并不是一个完整的数据流。
HLS 协议在服务器端将直播数据流存储为连续的、很短时长的媒体文件(MPEG-TS格式),而客户端则不断的下载并播放这些小文件,因为服务器端总是会将最新的直播数据生成新的小文件,这样客户端只要不停的按顺序播放从服务器获取到的文件,就实现了直播。由此可见,基本上可以认为,HLS 是以点播的技术方式来实现直播。由于数据通过 HTTP 协议传输,所以完全不用考虑防火墙或者代理的问题,而且分段文件的时长很短,客户端可以很快的选择和切换码率,以适应不同带宽条件下的播放。不过HLS的这种技术特点,决定了它的延迟一般总是会高于普通的流媒体直播协议。
7、WebRTC:
web端实现流媒体的协议。google刚推出WebRTC的时候巨头们要么冷眼旁观,要么抵触情绪很大。使用RTP协议传输
8、RTMP
RTMP(Real Time Messaging Protocol)实时消息传送协议
是Adobe Systems公司为Flash播放器和服务器之间音频、视频和数据传输开发的开放协议。它有三种变种:
1)工作在TCP之上的明文协议,使用端口1935;
2)RTMPT封装在HTTP请求之中,可穿越防火墙;
3)RTMPS类似RTMPT,但使用的是HTTPS连接;RTMP协议(Real Time Messaging Protocol)是被Flash用于对象,视频,音频的传输.这个协议建立在TCP协议或者轮询HTTP协议之上.RTMP协议就像一个用来装数据包的容器,这些数据既可以是AMF格式的数据,也可以是FLV中的视/音频数据.一个单一的连接可以通过不同的通道传输多路网络流.这些通道中的包都是按照固定大小的包传输的.
RTMP VS TCP&UDP
. TCP为点对点的协议,
这意味着各个客户需要分开客户机/服务器链接,因而无法在网络级实现对多个客户机的数据广播。
如果有一个数据流必须同时被传送到多个客户机,服务器必须传送数据流的副本到各个客户机,
TCP能够根据网络带宽和拥挤程度动态地调节传送速度并重新发送丢失的数据包,这样虽然保证了数据传输的可靠性,
但是对服务器资源耗费较大,在数据流大的场合难以保证数据流传输的实时性。
. UDP为不可靠传输协议,
在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度,计算机的能力和传输带宽的限制;
在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
UDP协议不需要维护连接状态,也不认为每个数据包都必须到达接受端,因此网络负荷比TCP小,传输速度也要比TCP快;
但在网络越拥挤时,越有更多的数据包丢失。
. RTMP协议是一个专门为高效传输视频,音频和数据而设计的协议。
它通过建立一个二进制TCP连接或者连接HTTP隧道实现实时的视频和声音传输。
共享对象是RTMP数据中一种比较重要的数据类型,任何客户端改变数据时,共享对象能够及时更新服务器端的数据,
这样,每个客户端都能够及时了解到数据的变化。
RTMP比传统媒介服务器流出的媒介协议支持更多。
它支持可能包含声音,影像和脚本数据从服务器到客户和从客户到服务器多条线路的动态传输。RTMP对声音、影像和脚本数据分别处理。
声音和视频数据被分开地缓冲在服务器中。
如果声音数据在声音缓冲器中达到某一极限,所有在缓冲器中的数据将被丢掉,
并且最近到达的数据被允许开始收集在缓冲中并被送到各个客户。
视频数据被以相似的方式处理,不同是当新的关键帧到达时,缓冲器中数据才被清除。
在丢掉旧的帧数据时,如果发现客户端的数据有误,则将新旧两个不同的帧进行拟合。
RTMP对数据给予不同的优先级别。
在实时交谈中,声音是最重要的,影像给予低优先级,而脚本数据被给予的优先权介于声音和影像中间。
RTMP协议可以创建多个数据流,但是每个数据流只能有一个方向。
使用RTMP可以构建这样的一个系统,客户端可以同时与RTMP服务器和应用服务器进行交互,使得服务端的负荷得以分散,
虽然在这种改进的系统结构中,RTMP服务器的性能要求比较高。
RTSP协议与HTTP协议区别
1 RTSP引入了几种新的方法,比如DESCRIBE、PLAY、SETUP 等,并且有不同的协议标识符,RTSP为rtsp 1.0,HTTP为http 1.1;2 HTTP是无状态的协议,而RTSP为每个会话保持状态;3 RTSP协议的客户端和服务器端都可以发送Request请求,而在HTTPF协议中,只有客户端能发送Request请求。4 在RTSP协议中,载荷数据一般是通过带外方式来传送的(除了交织的情况),及通过RTP协议在不同的通道中来传送载荷数据。而HTTP协议的载荷数据都是通过带内方式传送的,比如请求的网页数据是在回应的消息体中携带的。5 使用ISO10646(UTF-8) 而不是ISO 8859-1,以配合当前HTML的国际化;6 RTSP使用URI请求时包含绝对URI。而由于历史原因造成的向后兼容性问题,HTTP/1.1只在请求中包含绝对路径,把主机名放入单独的标题域中;
原文链接:https://blog.csdn.net/wangbuji/article/details/122416897
RTSP重要术语
1. 集合控制(Aggregatecontrol ):
对多个流的同时控制。对音频/视频来讲,客户端仅需发送一条播放或者暂停消息就可同时控制音频流和视频流。2. 实体(Entity):
作为请求或者回应的有效负荷传输的信息。由以实体标题域(entity-header field)形式存在的元信息和以实体主体(entity body)形式存在的内容组成3. 容器文件(Containerfile):
可以容纳多个媒体流的文件。RTSP服务器可以为这些容器文件提供集合控制。4. RTSP会话(RTSP session ):
RTSP交互的全过程。对一个电影的观看过程,会话(session)包括由客户端建立媒体流传输机制(SETUP),使用播放(PLAY)或录制(RECORD)开始传送流,用停止(TEARDOWN)关闭流。
RTSP方法,RTSP请求包括:OPTIONS,DESCRIBE,SETUP,PLAY,GET_PARAMETER,TEARDOWN。
简单的RTSP消息交互过程
C表示RTSP客户端,S表示RTSP服务端
服务器接收到OPTIONS请求后,将服务器能够提供的消息传给客户端。
服务器接收到DESCRIBE请求后,将SDP信息传给客户端。
服务器接收到SETUP请求后,建立RTP套接字,连接客户端RTP端口,等待发送RTP包。
服务器接收到拉流端PALY请求后,开始发送RTP包。
服务器接收到PAUSE 请求后,临时停止发送RTP包。使用 PLAY 来重新启动数据交互。ANNOUNCE:(1)C->S:客户端向服务器端发布URL指定的媒体信息描述;(2) S->C:实时更新对话描述。
RECORD:请求录制指定范围的媒体数据,请求中可指定录制的起止时间戳;若未指定时间范围,则使用presentation description中的开始和结束时间,这种情况下,如果会话已开始,则立即启动录制操作。
服务器接收到GET_PARAMETER请求后,将当前时间传递给客户端。
服务器接收到TEARDOWN请求后,停止发送RTP包,释放资源,停止接收RTSP请求,进入等待客户端连接状态。
三、测试 rtsp推拉流
1、rtsp推流
这里我们用FFmpeg来测试,关于移植FFmpeg这篇文章不讲,可以去别的文章搜索、我们事先准备好一个视频mp4文件。·用h264来解码视频,aac解音频。
推流到/live/buji1目录。在ubuntu下建立好这些文件,输入如下命令。
ffmpeg -re -i "/test.mp4" -vcodec h264 -acodec aac -f rtsp -rtsp_transport tcp rtsp://127.0.0.1/live/buji1
2、拉流
观看直播,浏览器访问http://127.0.0.1/buji/abc.mp4,点播
然后wirshark抓包
带有包序号的数据包,rtp协议传输的。
rtcp 传输的
一次基本的RTSP操作过程是:首先,客户端连接到流服务器并发送一个RTSP描述命令(DESCRIBE)。流服务器通过一个SDP描述来进行反馈,反馈信息包括流数量、媒体类型等信息。客户端再分析该SDP描述,并为会话中的每一个流发送一个RTSP建立命令(SETUP),RTSP建立命令告诉服务器客户端用于接收媒体数据的端口。流媒体连接建立完成后,客户端发送一个播放命令(PLAY),服务器就开始在UDP上传送媒体流(RTP包)到客户端。 在播放过程中客户端还可以向服务器发送命令来控制快进、快退和暂停等。最后,客户端可发送一个终止命令(TERADOWN)来结束流媒体会话
RTSP属于应用层协议,和HTTP类似,使用TCP传输,RTSP主要完成媒体信息交互,确认媒体传输方式和媒体传输控制,即RTSP负责上层控制,底层音视频传输使用的是其他的协议(RTP协议),RTSP交互过程中会把媒体信息告知对端,这个媒体信息就放在RTSP的payload(负载)中,和HTTP中的payload是一样的,在RTSP中媒体信息,也就是这个payload使用的是SDP协议,SDP协议就是规定了怎么描述媒体源(网络摄像头)包含哪些媒体流(主要是音频和视频)以及这些媒体流参数是怎么样的(音视频编解码参数等)。所以从IPC(网络摄像头)中获取音视频涉主要及到三个协议:RTSP、SDP、RTP。RTSP负责媒体控制,协商(确定传输方式,使用TCP还是UDP以及传输通道-TCP和传输端口-UDP);SDP负责描述媒体信息;RTP负责传输音视频。此外还有RTCP协议,是传输过程中对媒体质量进行控制(统计丢包,时延等),和RTP是一起使用的,不过RTCP协议是可选的,在具体应用中可以不实现RTCP协议。
SDP协议
v=0
o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
s=SDP Seminar
i=A Seminar on the session description protocol
u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
e=mjh@isi.edu (Mark Handley)
c=IN IP4 224.2.17.12/127
t=2873397496 2873404696
a=recvonly
m=audio 49170 RTP/AVP 0
m=video 51372 RTP/AVP 31
m=application 32416 udp wb
a=orient:portrait
上面是一个命令,对录制的视频文件推流的测试,下面是调用FFmpeg的api,使用rtsp推,实时的帧数据流订单例子
#include <libavformat/avformat.h>int main(int argc, char *argv[]) {AVFormatContext *format_ctx = NULL;AVOutputFormat *output_format = NULL;AVStream *stream = NULL;AVCodecContext *codec_ctx = NULL;AVCodec *codec = NULL;int ret;// 注册所有的格式和编解码器av_register_all();// 打开输出文件/接口if ((ret = avformat_alloc_output_context2(&format_ctx, NULL, "rtsp", "rtsp://your_rtsp_server/stream")) < 0) {fprintf(stderr, "Error allocating output context: %s\n", av_err2str(ret));goto end;}output_format = format_ctx->oformat;// 创建一个新的流if (!(stream = avformat_new_stream(format_ctx, NULL))) {fprintf(stderr, "Failed allocating stream\n");ret = AVERROR_UNKNOWN;goto end;}stream->id = format_ctx->nb_streams-1;// 找到编码器codec_ctx = stream->codec;codec_ctx->codec_id = output_format->video_codec;codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; // 或者你需要的其他像素格式codec_ctx->width = 640; // 视频宽度codec_ctx->height = 480; // 视频高度codec_ctx->time_base = (AVRational){1, 25}; // 时基为25fpscodec_ctx->bit_rate = 400000; // 设置码率if ((ret = avio_open(&format_ctx->pb, format_ctx->filename, AVIO_FLAG_WRITE)) < 0) {fprintf(stderr, "Could not open output URL '%s'", format_ctx->filename);goto end;}// 打开编解码器并设置编解码器参数codec = avcodec_find_encoder(codec_ctx->codec_id);if (!codec) {fprintf(stderr, "Codec not found\n");ret = AVERROR_UNKNOWN;goto end;}if ((ret = avcodec_open2(codec_ctx, codec, NULL)) < 0) {fprintf(stderr, "Failed to open codec: %s\n", av_err2str(ret));goto end;}// 写入文件头if ((ret = avformat_write_header(format_ctx, NULL)) < 0) {fprintf(stderr, "Error occurred when opening output file: %s\n", av_err2str(ret));goto end;}// 编码帧并写入输出// ...end:avformat_free_context(format_ctx);return ret < 0;
}
RTSP是C/S模型,RTSP服务端可向RTSP客户端发送音视频(客户端拉流模式),也可接受来自RTSP客户端发送过来的音视频流(客户端推流模式),RTSP拉流模式使用的方法包括DESCRIBE、SETUP、PLAY。RTSP推流模式使用的方法包括ANNOUNCE、SETUP、RECORD。其他的方法都是推流模式和拉流模式通用的。一般RTSP使用的都是拉流模式,即IPC作为RTSP服务端,RTSP客户端通过DESCRIBE、SETUP、PLAY等方法从IPC拉取音视频流。客户端推流一般使用另外一种协议RTMP,RTMP本系列中不会介绍。RTSP拉流模式和推流模式,基本类似,推拉流模式只是媒体流向不同,使用的方法不同,其他大同小异。本文主要对拉流模式也是目前IPC的音视频传输都在用的模式进行详细介绍。
下面是RTSP拉流信令交互过程。其中RTP是传输音视频数据,RTCP是音视频质量控制。
前面说过RTSP是交互媒体信息,确定数据传输方式的。其中传输方式包括TCP和UDP,UDP又包括单播和组播,下面将对每种方式进行数据包分析。
下面是wireshark抓取的RTSP数据包(仅包含一路媒体流,SETUP仅请求一次):
单播:UDP
1、OPTIONS
OPTINOS是客户端查询服务端支持哪些方法。
2、DESCRIBE
DESCRIBE是客户端请求服务端返回关于音视频的描述,用SDP表示。
3、SETUP
SETUP是请求音视频,这里只有视频并且视频的control是track0,如果还要音频的话就还需要再发起一次SETUP请求,请求音频数据。RTP/AVP表示使用UDP传输音视频数据,cilent_port中记录了客户端的RTP和RTCP数据接收端口,响应中server_port表示服务端的RTP和RTCP数据发送端口,
规定RTCP端口 = RTP端口 + 1。此外SETUP响应包中还会包含Session字段,表示当前会话,后面客户端请求都要带上这个Session字段,服务器用Session区分不同的客户端。
4、PLAY
5、TEARDOWN
客户端与服务端断开连接,媒体结束。
RTP /TCP/RTSP
当使用TCP协议承载RTSP/RTP时,所有的命令和媒体数据都将通过RTSP端口,RTP数据发送使用RTSP的socket和端口,数据将经过二元交织格式化之后才能发送。
要使用TCP连接,RTSP客户端需要在SETUP阶段请求TCP连接。SETUP命令中应该包括如下格式的Transport:
Transport: RTP/AVP/TCP;interleaved=0-1
上述Transport将告诉服务端使用TCP协议发送媒体数据,并且使用信道 0 和 1 对流数据以及控制信息进行交织。详细说来,使用偶数信道作为数据传输信道,使用奇数信道作为控制信道(数据信道 + 1)。所以,如果你设定数据信道为 0 ,那控制信道应该是 0 + 1 = 1。
RTP,RTCP数据和RTSP数据共享TCP数据通道,所以必须有一个标识来区别三种数据。
RTP和RTCP数据会以$符号+1个字节的通道编号+2个字节的数据长度,共4个字节的前缀开始,RTSP数据是没有前缀数据的。RTP数据和RTCP数据的区别在于第二个字节的通道编号,
RTP基于TCP的包头比基于UDP的包头多了4个字节:
* magic固定为0x24,
* channel用来区分音视频等多路流媒体的通道,其中偶数通道为流媒体内容,奇数通道为RTCP
* len表示数据包的长度减去开始的4个字节,即len字段之后的数据长度
五、总结
一个完整的RTSP流媒体传输过程是:
1、RTSP信令交互阶段:
客户端发起RTSP连接请求到服务端。
服务端响应,建立RTSP连接。
客户端与服务端交互,协商媒体传输方式(例如,使用UDP或TCP)。
服务端确认传输方式,建立媒体传输通道。
2、采集音视频阶段:
服务端开始采集音频和视频数据。
3、音视频编码阶段:
服务端进行H.264/H.265视频编码和AAC/PCM/PCMA/PACMU音频编码。
4、RTP封装阶段:
服务端将编码后的音视频数据封装成RTP数据包。
视频使用H.264/H.265 RTP封装,音频使用AAC/PCM/PCMA/PACMU RTP封装。
5、RTP数据传输阶段:
使用选择的传输方式(UDP或TCP),服务端将RTP数据包发送到客户端。
6、客户端接收与解包阶段:
客户端接收RTP数据包。
如果使用UDP传输,客户端直接解包RTP数据。
如果使用TCP传输,客户端从RTSP信令中获取通道信息,然后通过TCP连接接收RTP数据。
7、解码与播放阶段:
客户端对接收到的音视频数据进行解码。
解码后的数据传递给播放器进行播放。
我自己在做实时播放时,采用私有协议,只有自己定制的头,封装,直接tcp发送,不使用这么复杂的协议,浪费时间。