• 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

      

  • 相关阅读:
    java实现第九届蓝桥杯最大乘积
    java实现第九届蓝桥杯最大乘积
    Anaconda入门使用指南
    Java安全——密钥那些事
    关于keyGenerator,KeyPairGenerator,SecretKeyFactory的解析
    @Transactional事务几点注意
    三种方式都是通过某种公开的算法将原始信息进行编码 /加密
    信息摘要算法 MessageDigestUtil
    Java使用RSA加密解密签名及校验
    java util
  • 原文地址:https://www.cnblogs.com/wanggang123/p/6397594.html
Copyright © 2020-2023  润新知