Red5 Source Analysis-command processing for clients and servers
In the Red5 source analysis-5, you can know that after the rtmp handshake, the client sends the CONNECT command to the server, and the main function of the Connect command is to connect to a scope on the Red5 server, and when the connection is complete, a bandwidth-coordinated instruction is sent to the client. Ping instructions, and a bandwidth detection instruction. The ping instructions are analyzed first.
ping command service-side code
Here, let's stick to the ping instruction code issued after the server connects the client to a scope.
... 0, -1)); ...
The Ping constructor is very simple, it is some basic assignment, the following is the ping function of Conn,
ping(Pingping) { getChannel(2).write(ping); }
So this is simply sent to the client.
Client code
After the client receives a ping message from the server, according to the analysis in the previous chapters, the final call to Basertmpclienthandler's onping function,
protected void onping (Rtmpconnection conn, channel Channel, Header Source,Ping Ping) {switch (Ping. Geteventtype()) {casePing. PING_client:casePing. STREAM_begin:casePing. RECORDED_stream:casePing. STREAM_playbuffer_clear:PingPong = newPing();Pong. Seteventtype(Ping. PONG_server);Pong. SetValue2 ((int) (System. Currenttimemillis() &0xFFFFFFFF));Conn. Ping(Pong); Break;CasePing. STREAM_dry: Break;CasePing. CLIENT_buffer: ... Break;CasePing. PING_swf_verify: ... Break;CasePing. BUFFER_empty: Break;CasePing. BUFFER_full: Break;Default:}}
Because the EventType of the ping command sent by the server is Stream_begin, the client sends its current number of milliseconds to the server only as seen in the previous section. Next look at server-side processing.
Service-side code
After the server receives the client's Pong_server message, it eventually enters the Rtmphandler onping function, which is the following code
source, Ping ping) { switch (ping.getEventType()) { case Ping.CLIENT_BUFFER: ... break; case Ping.PONG_SERVER: conn.pingReceived(ping); break; default: } }
Here, call Rtmpminaconnection's pingreceived function directly, as defined below
Public void pingreceived(Ping Pong) {Longnow = System.currenttimemillis (); Number Previouspingvalue = Lastpingsenton.Get() &0xFFFFFFFF;if(pong.getvalue2 () = = Previouspingvalue) {Lastpingroundtriptime.Set((int) (Now &0xFFFFFFFF)-Pong.getvalue2 (). Intvalue ()); }Else{if(Getpendingmessages () >4) {Number Pingrtt = (now &0xFFFFFFFF)-Pong.getvalue2 (). Intvalue (); }} Lastpongreceivedon.Set(now); }
Here is a simple assignment that records the individual result values of this ping.
Processing server-side code for long connections
Now that we're talking about Ping, here's an analysis of the Keepalivetask in the previous chapter, which appears in the Startroundtripmeasurement function,
... keepAliveTask = scheduler.scheduleAtFixedRate(new KeepAliveTask(), pingInterval); ...
This task is used to keep a long connection, as seen below,
Public void Run() {if(state.getstate () = = RTMP. state_connected) {if(Running.compareandset (false,true)) {Try{if(IsConnected ()) {Longnow = System.currenttimemillis ();LongCurrentreadbytes = Getreadbytes ();LongPreviousreadbytes = Lastbytesread.Get();if(Currentreadbytes > Previousreadbytes) {if(Lastbytesread.compareandset (Previousreadbytes, currentreadbytes)) {lastbytesreadtime = now; }if(Isidle ()) {oninactive (); } }Else{LongLastpingtime = Lastpingsenton.Get();LongLastpongtime = Lastpongreceivedon.Get();if(Lastpongtime >0&& (Lastpingtime-lastpongtime > Maxinactivity) && (Now-lastbytesreadtime > Maxinactivity)) { Oninactive (); }Else{ping (); } } }Else{oninactive (); } }Catch(Exception e) { }finally{Running.compareandset (true,false); } } } }
First, if there is data read in each Keepalivetask boot gap, check the ping status through Isidle,
publicisIdle() { long lastPingTime = lastPingSentOn.get(); long lastPongTime = lastPongReceivedOn.get(); 0 && (lastPingTime - lastPongTime > maxInactivity)); return idle; }
Lastpingtime represents the time of the most recent ping, lastpongtime indicates the last time the client ping was appropriate, and their difference would indicate how long the last time the client responded to the ping, and when this time was exceeded, Indicates that the server sent a number of ping requests but the client is not responding, so return true, and then call Oninactive to close the connection.
Back to Keepalivetask, assuming that the server in the Keepalivetask start gap no data read, it is necessary to determine whether it has not responded to the ping request for a long time, and has not been read into the data, "long" boundary is maxinactivity, If it is satisfied, the connection is closed and if it is not satisfied, the ping is sent to the client. Here, the ping function without the reference is as follows,
public void ping () {long newpingtime = system.cu Rrenttimemillis (); if (Lastpingsenton. get () = = 0 ) {lastpongreceivedon. Set (Newpingtime); } Ping pingrequest = new ping (); Pingrequest.seteventtype (ping.ping_client); Lastpingsenton. set (Newpingtime); int now = (int ) (Newpingtime & 0xffffffff ); Pingrequest.setvalue2 (now); Ping (pingrequest); }
The above mentioned Lastpingsenton is set here, mainly the event type changes in order to ping_client, but the client is handled in the same way as the previous event type Stream_begin, so the down is not analyzed.
Bandwidth command server-side code
When the client sends the CONNECT command to connect to the server scope, during the connection process, the server sends two and bandwidth-related instructions back to the client, this code is as follows,
two.write(new ServerBW(defaultServerBandwidth)); two.write(new ClientBW(defaultClientBandwidth, (byte) limitType));
Therefore, the SERVERBW and CLIENTBW two classes are sent, and their corresponding datatype are type_server_bandwidth and type_client_bandwidth respectively.
Client code
According to the above-mentioned datatype, when the bandwidth information arrives at the client, the Onserverbandwidth and onclientbandwidth are called respectively for processing,
protected void Onserverbandwidth(Rtmpconnection conn, channel Channel, SERVERBW message) {intBandwidth = Message.getbandwidth ();if(Bandwidth! = Bytesreadwindow) {CLIENTBW CLIENTBW =NewCLIENTBW (Bandwidth, (byte)2); Channel.write (CLIENTBW); } }protected void Onclientbandwidth(Rtmpconnection conn, channel Channel, CLIENTBW message) {intBandwidth = Message.getbandwidth ();if(Bandwidth! = Byteswrittenwindow) {SERVERBW SERVERBW =NewSERVERBW (bandwidth); Channel.write (SERVERBW); } }
Regardless of the bandwidth that is received, this is compared to the local window, and if not equal, it is sent to the server. You can modify this part of the code to adjust the client bandwidth.
Server-side code
After the server receives the feedback from the client, the local onserverbandwidth and Onclientbandwidth functions are also called to continue processing, but the two functions are empty functions on the server side, that is, the server does nothing.
Checkbandwidth Command server-side code
Similarly, the Checkbandwidth command is sent when the Connect command is processed on the server side, with the following code:
publicvoidcheckBandwidth() { new ServerClientDetection(); detection.checkBandwidth(Red5.getConnectionLocal()); }
The Serverclientdetection constructor is empty, so look directly at the Checkbandwidth function,
publicvoidcheckBandwidth(IConnection conn) { calculateClientBw(conn); } publicvoidcalculateClientBw(IConnection conn) { this.conn = conn; new Random(); rnd.nextBytes(payload); rnd.nextBytes(payload1); startBytesWritten = conn.getWrittenBytes(); startTime = System.nanoTime(); callBWCheck(""); }
Payload and Payload1 are two random arrays, Startbyteswritten records the number of bytes emitted by the connection, StartTime is the current nanosecond number, the most critical is the last Call of Callbwcheck,
PrivatevoidCallbwcheck (ObjectPayload) {Iconnection conn = red5.getconnectionlocal (); map<String,Object> statsvalues =Newhashmap<String,Object> (); Statsvalues.put ("Count", Packetsreceived.get ()); Statsvalues.put ("Sent", Packetssent.get ()); Statsvalues.put ("timepassed", timepassed); Statsvalues.put ("Latency", latency); Statsvalues.put ("Cumlatency", cumlatency); Statsvalues.put ("Payload", payload);if(Conninstanceofiservicecapableconnection) {packetssent.incrementandget (); ((iservicecapableconnection) conn). Invoke ("Onbwcheck",New Object[] {statsvalues}, This); } }
After the corresponding setting, the Invoke function of call rtmpminaconnection is sent, and the function is defined as follows.
publicmethod, Object[] params, IPendingServiceCallback callback) { IPendingServiceCall call = new PendingCall(method, params); if (callback != null) { call.registerCallback(callback); } invoke(call); }
Therefore, the callback function is registered here, and then the invoke request is sent to the client.
Client code
The client's corresponding Onbwcheck function is empty, and the handler function is just the original data return, so this is not seen here.
Server-side code
The corresponding code on the server side is also empty, so it is left to the developer to add functions for processing.
Red5 Source Analysis---6