CrtmpServr 接收Http流程

    最近在研究CrtmpServer http部分,记录一些基本的流程,以备查阅。

首先,打开配置脚本CrtmpServer.lua ,确认脚本中有以下内容,如果没有需要加上。

{
            name="samplefactory",
            description="asdsadasdsa",
            protocol="dynamiclinklibrary",
            aliases=
            {
                "httpOutboundTest"
            },
            acceptors = 
            {
                {
                    ip="0.0.0.0",
                    port=8989,
                    protocol="httpEchoProtocol"
                },
                {
                    ip="0.0.0.0",
                    port=8988,
                    protocol="echoProtocol"
                }
            }
            --validateHandshake=true,
            --default=true,
        },

     在浏览器地址栏中输入http://127.0.0.1:8989/httpEchoProtocol/TestHttp,跟踪CrtmpServer堆栈,调用堆栈如下图所示。

                                                       图1 CrtmpServer接收Http调用堆栈

下面逐步分析流程:

1.TCPCarrier::OnEvent(select_event &event)

      Carrier层要么是udp,要么是tcp,http协议传输层采用的是http,所以是接收到Tcp链接。

  CrtmpServer运行后通过Register 将Http,Tcp协议注册到一起。代码如下:

vector<uint64_t> ProtocolFactory::ResolveProtocolChain(string name) {
	vector<uint64_t> result;
	if (name == "echoProtocol") {
		ADD_VECTOR_END(result, PT_TCP);
		ADD_VECTOR_END(result, PT_ECHO_PROTOCOL);
	} else if (name == "httpEchoProtocol") {
		ADD_VECTOR_END(result, PT_TCP);
		ADD_VECTOR_END(result, PT_INBOUND_HTTP);
		ADD_VECTOR_END(result, PT_ECHO_PROTOCOL);
	} else if (name == "httpDownload") {
		ADD_VECTOR_END(result, PT_TCP);
		ADD_VECTOR_END(result, PT_OUTBOUND_HTTP);
		ADD_VECTOR_END(result, PT_HTTP_DOWNLOAD_PROTOCOL);
	} else {
		ASSERT("This protocol stack should not land here");
	}
	return result;
}

 这段代码的调用流程如下图所示:

                   图2 httpEchoProtocol流程

tcp 从tcp链接缓存中读取数据代码如下,读取的数据放在pInputBuffer.

 

bool TCPCarrier::OnEvent(select_event &event) {
	int32_t readAmount = 0;
	int32_t writeAmount = 0;

	//3. Do the I/O
	switch (event.type) {
		case SET_READ:
		{
			IOBuffer *pInputBuffer = _pProtocol->GetInputBuffer();
			assert(pInputBuffer != NULL);
			if (!pInputBuffer->ReadFromTCPFd(_inboundFd,
					_recvBufferSize, readAmount)) {
				FATAL("Unable to read data. %s:%hu -> %s:%hu",
						STR(_farIp), _farPort,
						STR(_nearIp), _nearPort);
				return false;
			}
			_rx += readAmount;
			return _pProtocol->SignalInputData(readAmount);
		}

  2. 看下tcp procotol signalInputData代码  

bool TCPProtocol::SignalInputData(int32_t recvAmount) {
	_decodedBytesCount += recvAmount;
	return _pNearProtocol->SignalInputData(_inputBuffer);
}

 _inputBuffer 中的内容如下,httpEchoProtocol/TestHttp 即是在浏览器地址上输入的http地址。

GET /httpEchoProtocol/TestHttp HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:8989
Connection: Keep-Alive

  3. _pNearProtocol 实际上是BaseHTTPProtocol. _pNearProtocol->SignalInputData实际调用是BaseHTTPProtocol::SignalInputData。

SignalInputData 调用 HandleFixedLengthContent 方法,该方法会将http内容传给具体EchoProtocol,方法内容如下:

bool BaseHTTPProtocol::HandleFixedLengthContent(IOBuffer &buffer) {
	//1. Compute the chunk size that we areg going to read
	//which is how many bytes we have available, but no more than _contentLength
	uint32_t chunkSize = GETAVAILABLEBYTESCOUNT(buffer);
	assert(_sessionDecodedBytesCount <= _contentLength);
	uint32_t remaining = _contentLength - _sessionDecodedBytesCount;
	chunkSize = chunkSize > remaining ? remaining : chunkSize;

	//2. Update the session decoded bytes count and decoded bytes count
	_sessionDecodedBytesCount += chunkSize;
	_decodedBytesCount += chunkSize;

	//3. Make the copy and ignore the chunk size
	_inputBuffer.ReadFromBuffer(GETIBPOINTER(buffer), chunkSize);
	buffer.Ignore(chunkSize);

	//3. Call the near protocol
	if (!_pNearProtocol->SignalInputData(_inputBuffer)) {
		FATAL("Unable to call the next protocol in stack");
		return false;
	}

	//4. reset the state if necessary
	if (TransferCompleted()) {
		_headers.Reset();
		_contentLength = 0;
		_chunkedContent = false;
		_lastChunk = false;
		_state = HTTP_STATE_HEADERS;
		_sessionDecodedBytesCount = 0;
	}

	//5. we are done
	return true;
}

  _pNearProtocol 实际是EchoProtocol

 

 

  

 

posted @ 2017-02-14 14:49  王纲  阅读(703)  评论(0编辑  收藏  举报