From 960341b9b2b9646270ccfd113b4dd784d9826c73 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 24 May 2015 22:43:02 +0800 Subject: [PATCH] for #405, improve the HTT FLV to 3k. 2.0.169 --- README.md | 4 +- trunk/src/app/srs_app_http_conn.cpp | 81 +++++++++++++++++++++++++-- trunk/src/app/srs_app_http_conn.hpp | 8 ++- trunk/src/core/srs_core.hpp | 2 +- trunk/src/kernel/srs_kernel_file.cpp | 22 ++++++++ trunk/src/kernel/srs_kernel_file.hpp | 10 ++++ trunk/src/kernel/srs_kernel_flv.cpp | 29 ++++------ trunk/src/protocol/srs_http_stack.hpp | 10 ++++ 8 files changed, 140 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 603aadc357..0aa2d2564e 100755 --- a/README.md +++ b/README.md @@ -716,7 +716,8 @@ The play HTTP FLV benchmark by [SB](https://github.com/simple-rtmp-server/srs-be | Update | SRS | Clients | Type | CPU | Memory | Commit | | ------------- | --------- | ------------- | ------------- | --------- | -------- | ------------ | | 2014-05-24 | 2.0.167 | 1.0k(1000) | players | 82% | 86MB | - | -| 2014-05-24 | 2.0.168 | 2.3k(2300) | players | 92% | 276MB | - | +| 2014-05-24 | 2.0.168 | 2.3k(2300) | players | 92% | 276MB | [code][p17] | +| 2014-05-24 | 2.0.169 | 3.0k(3000) | players | 94% | 188MB | [code][p18] | ### Latency benchmark @@ -832,6 +833,7 @@ Winlin [p14]: https://github.com/simple-rtmp-server/srs/commit/10297fab519811845b549a8af40a6bcbd23411e8 [p15]: https://github.com/simple-rtmp-server/srs/commit/0d6b91039d408328caab31a1077d56a809b6bebc [p16]: https://github.com/simple-rtmp-server/srs/commit/0d6b91039d408328caab31a1077d56a809b6bebc +[p17]: https://github.com/simple-rtmp-server/srs/commit/fc995473eb02c7cf64b5b212b456e11f34aa7984 [authors]: https://github.com/simple-rtmp-server/srs/blob/develop/AUTHORS.txt [bigthanks]: https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Product#bigthanks diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index e095dfee7a..682d936fba 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -98,8 +98,14 @@ int SrsHttpResponseWriter::write(char* data, int size) if (!header_wrote) { write_header(SRS_CONSTS_HTTP_OK); + + if ((ret = send_header(data, size)) != ERROR_SUCCESS) { + srs_error("http: send header failed. ret=%d", ret); + return ret; + } } + // check the bytes send and content length. written += size; if (content_length != -1 && written > content_length) { ret = ERROR_HTTP_CONTENT_LENGTH; @@ -107,11 +113,6 @@ int SrsHttpResponseWriter::write(char* data, int size) return ret; } - if ((ret = send_header(data, size)) != ERROR_SUCCESS) { - srs_error("http: send header failed. ret=%d", ret); - return ret; - } - // ignore NULL content. if (!data) { return ret; @@ -143,6 +144,71 @@ int SrsHttpResponseWriter::write(char* data, int size) return ret; } +int SrsHttpResponseWriter::writev(iovec* iov, int iovcnt, ssize_t* pnwrite) +{ + int ret = ERROR_SUCCESS; + + // when header not ready, or not chunked, send one by one. + if (!header_wrote || content_length != -1) { + ssize_t nwrite = 0; + for (int i = 0; i < iovcnt; i++) { + iovec* piovc = iov + i; + nwrite += piovc->iov_len; + if ((ret = write((char*)piovc->iov_base, (int)piovc->iov_len)) != ERROR_SUCCESS) { + return ret; + } + } + + if (pnwrite) { + *pnwrite = nwrite; + } + + return ret; + } + + // ignore NULL content. + if (iovcnt <= 0) { + return ret; + } + + // send in chunked encoding. + int nb_iovss = iovcnt * 4; + iovec* iovss = new iovec[nb_iovss]; + SrsAutoFree(iovec, iovss); + + char* pheader_cache = header_cache; + for (int i = 0; i < iovcnt; i++) { + int left = SRS_HTTP_HEADER_CACHE_SIZE - (int)(pheader_cache - header_cache); + srs_assert(left > 0); + + iovec* data_iov = iov + i; + int nb_size = snprintf(pheader_cache, left, "%x", (int)data_iov->iov_len); + + iovec* iovs = iovss + (i * 4); + iovs[0].iov_base = (char*)pheader_cache; + iovs[0].iov_len = (int)nb_size; + iovs[1].iov_base = (char*)SRS_HTTP_CRLF; + iovs[1].iov_len = 2; + iovs[2].iov_base = (char*)data_iov->iov_base; + iovs[2].iov_len = (int)data_iov->iov_len; + iovs[3].iov_base = (char*)SRS_HTTP_CRLF; + iovs[3].iov_len = 2; + + pheader_cache += nb_size; + } + + ssize_t nwrite; + if ((ret = skt->writev(iovss, nb_iovss, &nwrite)) != ERROR_SUCCESS) { + return ret; + } + + if (pnwrite) { + *pnwrite = nwrite; + } + + return ret; +} + void SrsHttpResponseWriter::write_header(int code) { if (header_wrote) { @@ -1513,6 +1579,11 @@ int SrsStreamWriter::write(void* buf, size_t count, ssize_t* pnwrite) return writer->write((char*)buf, (int)count); } +int SrsStreamWriter::writev(iovec* iov, int iovcnt, ssize_t* pnwrite) +{ + return writer->writev(iov, iovcnt, pnwrite); +} + SrsLiveStream::SrsLiveStream(SrsSource* s, SrsRequest* r, SrsStreamCache* c) { source = s; diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index 6e7c1d727e..c6ec027953 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -71,7 +71,11 @@ class SrsHttpMessage; #ifdef SRS_AUTO_HTTP_PARSER -#define SRS_HTTP_HEADER_CACHE_SIZE 16 +// for HTTP FLV, each video/audio packet is send by 3 iovs, +// while each iov is send by 4 sub iovs, that is needs 3 chunk header, +// suppose each header is 16 length, 3*16=48 is ok. +// that is, 512 can used for 16 iovs to send. +#define SRS_HTTP_HEADER_CACHE_SIZE 512 /** * response writer use st socket @@ -105,6 +109,7 @@ class SrsHttpResponseWriter : public ISrsHttpResponseWriter virtual int final_request(); virtual SrsHttpHeader* header(); virtual int write(char* data, int size); + virtual int writev(iovec* iov, int iovcnt, ssize_t* pnwrite); virtual void write_header(int code); virtual int send_header(char* data, int size); }; @@ -541,6 +546,7 @@ class SrsStreamWriter : public SrsFileWriter virtual int64_t tellg(); public: virtual int write(void* buf, size_t count, ssize_t* pnwrite); + virtual int writev(iovec* iov, int iovcnt, ssize_t* pnwrite); }; /** diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 93f6c16017..9b842b886d 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR 2 #define VERSION_MINOR 0 -#define VERSION_REVISION 168 +#define VERSION_REVISION 169 // server info. #define RTMP_SIG_SRS_KEY "SRS" diff --git a/trunk/src/kernel/srs_kernel_file.cpp b/trunk/src/kernel/srs_kernel_file.cpp index 40ef01305b..75410b568c 100644 --- a/trunk/src/kernel/srs_kernel_file.cpp +++ b/trunk/src/kernel/srs_kernel_file.cpp @@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include using namespace std; #include @@ -145,6 +146,27 @@ int SrsFileWriter::write(void* buf, size_t count, ssize_t* pnwrite) return ret; } +int SrsFileWriter::writev(iovec* iov, int iovcnt, ssize_t* pnwrite) +{ + int ret = ERROR_SUCCESS; + + ssize_t nwrite = 0; + for (int i = 0; i < iovcnt; i++) { + iovec* piov = iov + i; + ssize_t this_nwrite = 0; + if ((ret = write(piov->iov_base, piov->iov_len, &this_nwrite)) != ERROR_SUCCESS) { + return ret; + } + nwrite += this_nwrite; + } + + if (pnwrite) { + *pnwrite = nwrite; + } + + return ret; +} + SrsFileReader::SrsFileReader() { fd = -1; diff --git a/trunk/src/kernel/srs_kernel_file.hpp b/trunk/src/kernel/srs_kernel_file.hpp index 4943c1ed7e..167e8559d8 100644 --- a/trunk/src/kernel/srs_kernel_file.hpp +++ b/trunk/src/kernel/srs_kernel_file.hpp @@ -31,6 +31,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include +// for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213 +#ifndef _WIN32 +#include +#endif + /** * file writer, to write to file. */ @@ -62,6 +67,11 @@ class SrsFileWriter * @param pnwrite the output nb_write, NULL to ignore. */ virtual int write(void* buf, size_t count, ssize_t* pnwrite); + /** + * for the HTTP FLV, to writev to improve performance. + * @see https://github.com/simple-rtmp-server/srs/issues/405 + */ + virtual int writev(iovec* iov, int iovcnt, ssize_t* pnwrite); }; /** diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index 725a4401d6..04602845b6 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -223,31 +223,24 @@ int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_s { int ret = ERROR_SUCCESS; - // write tag header. - if ((ret = _fs->write(header, header_size, NULL)) != ERROR_SUCCESS) { - if (!srs_is_client_gracefully_close(ret)) { - srs_error("write flv tag header failed. ret=%d", ret); - } - return ret; - } - - // write tag data. - if ((ret = _fs->write(tag, tag_size, NULL)) != ERROR_SUCCESS) { - if (!srs_is_client_gracefully_close(ret)) { - srs_error("write flv tag failed. ret=%d", ret); - } - return ret; - } - // PreviousTagSizeN UI32 Size of last tag, including its header, in bytes. char pre_size[SRS_FLV_PREVIOUS_TAG_SIZE]; if ((ret = tag_stream->initialize(pre_size, SRS_FLV_PREVIOUS_TAG_SIZE)) != ERROR_SUCCESS) { return ret; } tag_stream->write_4bytes(tag_size + header_size); - if ((ret = _fs->write(pre_size, sizeof(pre_size), NULL)) != ERROR_SUCCESS) { + + iovec iovs[3]; + iovs[0].iov_base = header; + iovs[0].iov_len = header_size; + iovs[1].iov_base = tag; + iovs[1].iov_len = tag_size; + iovs[2].iov_base = pre_size; + iovs[2].iov_len = sizeof(SRS_FLV_PREVIOUS_TAG_SIZE); + + if ((ret = _fs->writev(iovs, 3, NULL)) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { - srs_error("write flv previous tag size failed. ret=%d", ret); + srs_error("write flv tag failed. ret=%d", ret); } return ret; } diff --git a/trunk/src/protocol/srs_http_stack.hpp b/trunk/src/protocol/srs_http_stack.hpp index 8b14aad0e5..a127156fad 100644 --- a/trunk/src/protocol/srs_http_stack.hpp +++ b/trunk/src/protocol/srs_http_stack.hpp @@ -33,6 +33,11 @@ #include #include +// for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213 +#ifndef _WIN32 +#include +#endif + class SrsFileReader; class SrsHttpHeader; class ISrsHttpMessage; @@ -188,6 +193,11 @@ class ISrsHttpResponseWriter // the initial 512 bytes of written data to DetectContentType. // @param data, the data to send. NULL to flush header only. virtual int write(char* data, int size) = 0; + /** + * for the HTTP FLV, to writev to improve performance. + * @see https://github.com/simple-rtmp-server/srs/issues/405 + */ + virtual int writev(iovec* iov, int iovcnt, ssize_t* pnwrite) = 0; // WriteHeader sends an HTTP response header with status code. // If WriteHeader is not called explicitly, the first call to Write