加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

FMS 调用 WEBSERVICE(2)

发布时间:2020-12-16 23:47:20 所属栏目:安全 来源:网络整理
导读:?Requirements Prerequisite knowledge You should be familiar with Macromedia Flash from Adobe and understand the basics of ActionScript in both Flash and Flash Media Server 2. It would also help to have a basic understanding of XML. User le

Prerequisite knowledge

You should be familiar with Macromedia Flash from Adobe and understand the basics of ActionScript in both Flash and Flash Media Server 2. It would also help to have a basic understanding of XML.

User level

Intermediate

Required products

  • Flash Professional?(Download trial)
  • Flash Media Server?(Download trial)

Sample files

  • fms_web_services.zip?(364 KB)

The design goal of any web service is to allow both developers and companies to share data easily. What makes this possible is the ability to output information in standard XML format so that programs written in different languages can communicate with the same service. You can also use your favorite language and platform to interface with Macromedia Flash Media Server 2 from Adobe.

Web services on the server side allow you to interact with your production servers without ever exposing the connection. By being free to develop in the language you want and still communicate with Flash Media Server,all you need to do is create a web service.

Flash Media Server 2 has some limitations on how web services handle complex data (objects) or an array returned by a web service. After some serious head scratching,I have attempted to draw out some of these limitations and describe to what extent you can still manipulate complex data types.

By way of example—a web service providing a weather forecast using the Web Service Description Language (WSDL)—this article attempts to explain not only how web services work in Flash Media Server 2 but detail some of the challenges you face when dealing with complex data types.

Exploring the simple forecast interface

In this section,I will go over the interface and the parameters required for the remote method.

There are many free web services on the Internet (XMethods,?WebserviceX.net,and so on). I will use one of the WebserviceX.net services for this article (see Figure 1).

Figure 1. Weather Forecast application relying on Flash Media Server web services to display the information

The end user simply submits a five-digit ZIP code to the service. There's no real error handling built in. When results are displayed,the Next and Prev buttons step the user through the upcoming days in the forecast.

Because there is a limit to the amount of data that Flash Media Server can receive from a web service,you may get mixed results with this weather forcast application. This web service provides a seven-day forecast but you will notice that,in most cases,you get a five-day forecast due to this limitation. The other result you may receive is an "Unable to connect to endpoint" message.

Note:?If you do receive an "Unable to connect to endpoint" message,enter a new ZIP code and try again. There is no need to recompile the client application or unload the server ASC file. Alternate between ZIP codes 33021,77077,33004,33309,77079,94105,10286,and 97070. Of course,you can use your own ZIP code—just remember that this is a free service and is not always available.

Point your browser to the following URL,which shows the XML structure definition for the Weather Forecast WSDL (see Listing 1). You should be able to see other methods that you could use,like?GetWeatherByPlaceName,which requires a parameter?PlaceName?of type?string:

http://www.webservicex.net/WeatherForecast.asmx?WSDL

For this exercise,I will focus on?GetWeatherByZipCode,which requires a parameter of type?string.

Listing 1.?Weather Forecast WSDL

<wsdl:definitions targetNamespace="http://www.webservicex.net"> <wsdl:types> <s:schema elementFormDefault="qualified" targetNamespace="http://www.webservicex.net"> <s:element name="GetWeatherByZipCode"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="ZipCode" type="s:string"/> </s:sequence> </s:complexType> </s:element> <s:element name="GetWeatherByZipCodeResponse"> <s:complexType> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="GetWeatherByZipCodeResult" type="tns:WeatherForecasts"/> </s:sequence> </s:complexType> </s:element> <s:complexType name="WeatherForecasts"> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="Latitude" type="s:float"/> <s:element minOccurs="1" maxOccurs="1" name="Longitude" type="s:float"/> <s:element minOccurs="1" maxOccurs="1" name="AllocationFactor" type="s:float"/> <s:element minOccurs="0" maxOccurs="1" name="FipsCode" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="PlaceName" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="StateCode" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="Status" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="Details" type="tns:ArrayOfWeatherData"/> </s:sequence> </s:complexType> <s:complexType name="ArrayOfWeatherData"> <s:sequence> <s:element minOccurs="0" maxOccurs="unbounded" name="WeatherData" type="tns:WeatherData"/> </s:sequence> </s:complexType> <s:complexType name="WeatherData"> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="Day" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="WeatherImage" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="MaxTemperatureF" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="MinTemperatureF" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="MaxTemperatureC" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="MinTemperatureC" type="s:string"/> </s:sequence> </s:complexType> <s:element name="GetWeatherByPlaceName"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="PlaceName" type="s:string"/> </s:sequence> </s:complexType> </s:element> <s:element name="GetWeatherByPlaceNameResponse"> <s:complexType> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="GetWeatherByPlaceNameResult" type="tns:WeatherForecasts"/> </s:sequence> </s:complexType> </s:element> <s:element name="WeatherForecasts" type="tns:WeatherForecasts"/> </s:schema> </wsdl:types> <wsdl:message name="GetWeatherByZipCodeSoapIn"> <wsdl:part name="parameters" element="tns:GetWeatherByZipCode"/> </wsdl:message> <wsdl:message name="GetWeatherByZipCodeSoapOut"> <wsdl:part name="parameters" element="tns:GetWeatherByZipCodeResponse"/> </wsdl:message> <wsdl:message name="GetWeatherByPlaceNameSoapIn"> <wsdl:part name="parameters" element="tns:GetWeatherByPlaceName"/> </wsdl:message> <wsdl:message name="GetWeatherByPlaceNameSoapOut"> <wsdl:part name="parameters" element="tns:GetWeatherByPlaceNameResponse"/> </wsdl:message> <wsdl:message name="GetWeatherByZipCodeHttpGetIn"> <wsdl:part name="ZipCode" type="s:string"/> </wsdl:message> <wsdl:message name="GetWeatherByZipCodeHttpGetOut"> <wsdl:part name="Body" element="tns:WeatherForecasts"/> </wsdl:message> <wsdl:message name="GetWeatherByPlaceNameHttpGetIn"> <wsdl:part name="PlaceName" type="s:string"/> </wsdl:message> <wsdl:message name="GetWeatherByPlaceNameHttpGetOut"> <wsdl:part name="Body" element="tns:WeatherForecasts"/> </wsdl:message> <wsdl:message name="GetWeatherByZipCodeHttpPostIn"> <wsdl:part name="ZipCode" type="s:string"/> </wsdl:message> <wsdl:message name="GetWeatherByZipCodeHttpPostOut"> <wsdl:part name="Body" element="tns:WeatherForecasts"/> </wsdl:message> <wsdl:message name="GetWeatherByPlaceNameHttpPostIn"> <wsdl:part name="PlaceName" type="s:string"/> </wsdl:message> <wsdl:message name="GetWeatherByPlaceNameHttpPostOut"> <wsdl:part name="Body" element="tns:WeatherForecasts"/> </wsdl:message> <wsdl:portType name="WeatherForecastSoap"> <wsdl:operation name="GetWeatherByZipCode"> <documentation> Get one week weather forecast for a valid Zip Code(USA) </documentation> <wsdl:input message="tns:GetWeatherByZipCodeSoapIn"/> <wsdl:output message="tns:GetWeatherByZipCodeSoapOut"/> </wsdl:operation> <wsdl:operation name="GetWeatherByPlaceName"> <documentation> Get one week weather forecast for a place name(USA) </documentation> <wsdl:input message="tns:GetWeatherByPlaceNameSoapIn"/> <wsdl:output message="tns:GetWeatherByPlaceNameSoapOut"/> </wsdl:operation> </wsdl:portType> <wsdl:portType name="WeatherForecastHttpGet"> <wsdl:operation name="GetWeatherByZipCode"> <documentation> Get one week weather forecast for a valid Zip Code(USA) </documentation> <wsdl:input message="tns:GetWeatherByZipCodeHttpGetIn"/> <wsdl:output message="tns:GetWeatherByZipCodeHttpGetOut"/> </wsdl:operation> <wsdl:operation name="GetWeatherByPlaceName"> <documentation> Get one week weather forecast for a place name(USA) </documentation> <wsdl:input message="tns:GetWeatherByPlaceNameHttpGetIn"/> <wsdl:output message="tns:GetWeatherByPlaceNameHttpGetOut"/> </wsdl:operation> </wsdl:portType> <wsdl:portType name="WeatherForecastHttpPost"> <wsdl:operation name="GetWeatherByZipCode"> <documentation> Get one week weather forecast for a valid Zip Code(USA) </documentation> <wsdl:input message="tns:GetWeatherByZipCodeHttpPostIn"/> <wsdl:output message="tns:GetWeatherByZipCodeHttpPostOut"/> </wsdl:operation> <wsdl:operation name="GetWeatherByPlaceName"> <documentation> Get one week weather forecast for a place name(USA) </documentation> <wsdl:input message="tns:GetWeatherByPlaceNameHttpPostIn"/> <wsdl:output message="tns:GetWeatherByPlaceNameHttpPostOut"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="WeatherForecastSoap" type="tns:WeatherForecastSoap"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/> <wsdl:operation name="GetWeatherByZipCode"> <soap:operation soapAction="http://www.webservicex.net/GetWeatherByZipCode" style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="GetWeatherByPlaceName"> <soap:operation soapAction="http://www.webservicex.net/GetWeatherByPlaceName" style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:binding name="WeatherForecastHttpGet" type="tns:WeatherForecastHttpGet"> <http:binding verb="GET"/> <wsdl:operation name="GetWeatherByZipCode"> <http:operation location="/GetWeatherByZipCode"/> <wsdl:input> <http:urlEncoded/> </wsdl:input> <wsdl:output> <mime:mimeXml part="Body"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="GetWeatherByPlaceName"> <http:operation location="/GetWeatherByPlaceName"/> <wsdl:input> <http:urlEncoded/> </wsdl:input> <wsdl:output> <mime:mimeXml part="Body"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:binding name="WeatherForecastHttpPost" type="tns:WeatherForecastHttpPost"> <http:binding verb="POST"/> <wsdl:operation name="GetWeatherByZipCode"> <http:operation location="/GetWeatherByZipCode"/> <wsdl:input> <mime:content type="application/x-www-form-urlencoded"/> </wsdl:input> <wsdl:output> <mime:mimeXml part="Body"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="GetWeatherByPlaceName"> <http:operation location="/GetWeatherByPlaceName"/> <wsdl:input> <mime:content type="application/x-www-form-urlencoded"/> </wsdl:input> <wsdl:output> <mime:mimeXml part="Body"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="WeatherForecast"> <documentation> Get one week weather forecast for valid zip code or Place name in USA </documentation> <wsdl:port name="WeatherForecastSoap" binding="tns:WeatherForecastSoap"> <soap:address location="http://www.webservicex.net/WeatherForecast.asmx"/> </wsdl:port> <wsdl:port name="WeatherForecastHttpGet" binding="tns:WeatherForecastHttpGet"> <http:address location="http://www.webservicex.net/WeatherForecast.asmx"/> </wsdl:port> <wsdl:port name="WeatherForecastHttpPost" binding="tns:WeatherForecastHttpPost"> <http:address location="http://www.webservicex.net/WeatherForecast.asmx"/> </wsdl:port> </wsdl:service></wsdl:definitions>

Examining the server-side code

On the server side,make sure you start by loading the?WebServices?class with the following:

load("webservices/WebServices.asc");

In this particular example,you are using remote method invocation (RMI) from the client to the server methodgetWeather:

Client.prototype.getWeather = function (zip){

Then you need a var of type?string?and?array?as well as the path to your service:

var aDetail=[];var Detailing="";var WSDLuri = "http://www.webservicex.net/WeatherForecast.asmx?WSDL";

Instantiate the?WebServices?class as follows,passing in the path to your service:

WeatherService = new WebService(WSDLuri);

Keep in mind that the?WebServices?class of Flash Media Server 2 provides you with two event handlers:?onLoad?andonFault?for both the WSDL and the result.

So you could use the following:

WeatherService.onLoad = function(Wsdl){ trace(Wsdl); } // onFault is triggered if the above load fails WeatherService.onFault = function(fault){ trace( fault.faultstring ); clientNow.call("failed",null,fault.faultstring); }

Once your?WebService?object is set,you need to fire an event on it using a function provided by the web services provider. Pointing your browser to the WSDL URL,you can view the XML definition as well as other descriptions. This allows you to view all available methods and their corresponding results.

As shown in Listing 1,pointing the browser to the URL reveals which methods are available to call within the XML code definition presented by the browser and how they will return the results.

Currently,you are concerned with the?GetWeatherByZipCode?method:

forcast =WeatherService.GetWeatherByZipCode(zip);

Once your method is called,you need to parse the result when?onResult?is triggered:

forcast.onResult = function(returning) { //convert result into an array aDetail for (var i in returning) { if (i == "Details") { for (var j in returning[i]) { switch (j) { case "xmlNodes" : //get rid of commas for (var p in returning[i][j]) { if (returning[i][j][p] != undefined) { aDetail.push(returning[i][j][p].toString()); } } case "length" : var total = returning[i][j]; } } } } var tot= aDetail.length; //push each array slot into the string Detailing to form xml string for (var i = 1; i<tot; ++i) { Detailing += aDetail[i]; } aDetail.splice(0); //now send xml string to client clientNow.call("forcast",Detailing); }

This process is rather elementary. All you're doing is working around the current?WebServices?class to handle an array. You use a "for in" loop to grab each element in the xmlNodes—part of the Details result—and pass it into the?aDetailarray you created earlier:

for (var p in returning[i][j]) { if (returning[i][j][p] != undefined) { aDetail.push(returning[i][j][p].toString()); }}

Once you have passed in all nodes,you can manipulate the array directly. Keep in mind that every web service returns results in its own way,so it is important to find a way to unfold your result. I have found that the most reliable way is to use the "for in" loop. Applying a "for in" loop showed some promise to the wealth of data returned. I then found other objects and set up "for in" loops in them,as well,until I had all the data I needed.

Note:?If you handle the processing on the client side,the "for in" loops will read backwards. Therefore,it is important to reverse the array (using?array.reverse()),once you have pushed the nodes into the array,to correct the order.

At this point you could use just the array to do what you want but my main objective is to get the data into its proposed XML format:

for (var i = 1; i<tot; ++i) { Detailing += aDetail[i];}

Push each node into the?Detailing?string and send to the client:

clientNow.call("forcast",Detailing);

Examining the client-side code

As you may be able to determine in Figure 1,I used three buttons ("Prev," "Next," and "Get Forecast"),a text input field (z_text),and a text area (T_text):

  • prev?button has the label "prev"
  • dnxt?has the label "next"
  • B?has the label "Get Forecast"
  • z_text?input field is for the ZIP code
  • T_text?text area displays the output information

In the Main.as class I have the following:

m_nc.forcast = function(returning):Void { this.owner.ReturnForcast(returning); };

which passes results to its own?ReturnForcast?method:

private function ReturnForcast(Detailing):Void { B.enabled = true; var my2_xml:XML = new XML(Detailing); var parentNode = my2_xml.childNodes; var xTotal:Number = parentNode.length; for (var i = 0; i<xTotal; ++i) { var subs:Number = parentNode[i].childNodes.length; var day = parentNode[i].childNodes[0].firstChild.nodeValue; var wImg = parentNode[i].childNodes[1].firstChild.nodeValue; var hF = parentNode[i].childNodes[2].firstChild.nodeValue; var lF = parentNode[i].childNodes[3].firstChild.nodeValue; var hC = parentNode[i].childNodes[4].firstChild.nodeValue; var lC = parentNode[i].childNodes[5].firstChild.nodeValue; aWeather.push([day,wImg,hF,lF,hC,lC]); }T_text.html = true;showWeather(); }

Once?ReturnFunction?uses the Flash Media Server string to create your XML,you can manipulate it into an array to be processed by?showWeather(). As I stated earlier,you could have also just sent the initial array from the server:

private function showWeather() { if (aWeather[current][0] != undefined) { T_text.text = ""; T_text.text += aWeather[current][0]+"<br>"; T_text.text += "<img src='"+aWeather[current][1]+"'><br>"; T_text.text += "high F="+aWeather[current][2]+"<br>"; T_text.text += "low F="+aWeather[current][3]+"<br>"; T_text.text += "high C="+aWeather[current][4]+"<br>"; T_text.text += "low C="+aWeather[current][5]+"<br>"; } prev.enabled =(current>0? true:false); dnxt.enabled =(current<aWeather.length?true:false); }

To make the actual remote method call from the client,use the?B("Get Forecast")?button's?click?event:

private function sendBtn() { var scope = this._parent; scope.current = 0; if (scope.z_text.text.length == 5) { scope.prev.enabled = false; scope.dnxt.enabled = false; scope.B.enabled = false; scope.m_nc.call("getWeather",scope.z_text.text); scope.T_text.text = "please waitn LOADING...."; } else { scope.T_text.text = "enter your 5digit zip code above"; }}

Reviewing the final code

Your final client-side code should look like this:

import mx.controls.*;//manipulation on Server sideclass Main extends MovieClip { private var current:Number = 0; private var Kconn:String = "rtmp:/webSD"; private var aWeather:Array = new Array(); private var T_text:TextArea; private var z_text:TextInput; private var B:Button; private var prev:Button; private var dnxt:Button; private var m_nc:NetConnection; function Main(Void) { this.attachMovie("TextInput","z_text",2,{_y:15}); z_text.setSize(74,22); this.attachMovie("TextArea","T_text",4,{_y:z_text._y+z_text.height+3}); T_text.setSize(178,141); T_text.html=false; T_text.wordWrap=true; trace("constructor inititalized!"); } //Called by the main timeline function connectMe(Void):Void { m_nc = new NetConnection(); m_nc.owner = this; m_nc.onStatus = function(info:Object):Void { this.owner.onConnectionStatus(info); }; m_nc.forcast = function(returning):Void { trace("try returning from server"+returning); this.owner.ReturnForcast(returning); }; m_nc.failed = function(failedString:String):Void { this.owner.Reset(failedString); }; m_nc.connect(Kconn); } private function onConnectionStatus(info:Object):Void { trace("nc.onStatus> info.code: "+info.code); if (info.code == "NetConnection.Call.Failed") { Reset(info.code); } if (info.description) { trace("nc.onStatus> info.description: "+info.description); } } //recieve forcast from the Server's webservice private function ReturnForcast(Detailing):Void { B.enabled = true; var my2_xml:XML = new XML(Detailing); var parentNode = my2_xml.childNodes; var xTotal:Number = parentNode.length; for (var i = 0; i<xTotal; ++i) { var subs:Number = parentNode[i].childNodes.length; var day = parentNode[i].childNodes[0].firstChild.nodeValue; var wImg = parentNode[i].childNodes[1].firstChild.nodeValue; var hF = parentNode[i].childNodes[2].firstChild.nodeValue; var lF = parentNode[i].childNodes[3].firstChild.nodeValue; var hC = parentNode[i].childNodes[4].firstChild.nodeValue; var lC = parentNode[i].childNodes[5].firstChild.nodeValue; aWeather.push([day,lC]); } //aWeather.reverse(); //trace("003 "+aWeather); T_text.html = true; showWeather(); } //produce visual representation of data stored in array private function showWeather() { //trace("004--> showWeather()"+current); if (aWeather[current][0] != undefined) { //::TODO proper error handling //(current == aWeather.length ? --current : ++current); T_text.text = ""; T_text.text += aWeather[current][0]+"<br>"; T_text.text += "<img src='"+aWeather[current][1]+"'><br>"; T_text.text += "high F="+aWeather[current][2]+"<br>"; T_text.text += "low F="+aWeather[current][3]+"<br>"; T_text.text += "high C="+aWeather[current][4]+"<br>"; T_text.text += "low C="+aWeather[current][5]+"<br>"; } prev.enabled =(current>0? true:false); dnxt.enabled =(current<aWeather.length?true:false); } private function Reset(failed:String) { trace("reset called"); T_text.text = failed; B.enabled = true; } //load public function onLoad(){ B.addEventListener("click",this.sendBtn); prev.addEventListener("click",this.prevBtn); dnxt.addEventListener("click",this.nextBtn); B.label = "Get Forecast"; prev.label = "prev"; dnxt.label = "next"; } //next button call private function nextBtn() { var scope = this._parent; ++scope.current; scope.showWeather(); } //prev button call private function prevBtn() { var scope = this._parent; --scope.current; scope.showWeather(); } //send(B) zip button call private function sendBtn() { var scope = this._parent; scope.current = 0; if (scope.z_text.text.length == 5) { scope.prev.enabled = false; scope.dnxt.enabled = false; scope.B.enabled = false; scope.m_nc.call("getWeather",scope.z_text.text); scope.T_text.text = "please waitn LOADING...."; } else { scope.T_text.text = "enter your 5digit zip code above"; } }}

Your final server-side code should look like this:

//most methods directly reflect the client side methods of webservicesload("webservices/WebServices.asc");application.onAppStart = function(){ }application.onConnect = function(N_client){ trace("user has connected"); application.acceptConnection(N_client); }Client.prototype.getWeather = function (zip){ var aDetail=[]; var Detailing=""; var clientNow=this; var WSDLuri = "http://www.webservicex.net/WeatherForecast.asmx?WSDL"; // Service Created WeatherService = new WebService(WSDLuri); // load WSDL WeatherService.onLoad = function(Wsdl){ trace("wsdl-->string"+Wsdl); } // onFault is triggered if the above load fails WeatherService.onFault = function(fault){ trace("wetherservice fault-->"+ fault.faultstring ); clientNow.call("failed",fault.faultstring); } //forcast is set to recieve result from the remote method "GetWeatherByZipCode" forcast =WeatherService.GetWeatherByZipCode(zip); // Grab the result forcast.onResult = function(returning) { //convert result into an array aDetail for (var i in returning) { if (i == "Details") { for (var j in returning[i]) { switch (j) { case "xmlNodes" : //get rid of commas for (var p in returning[i][j]) { if (returning[i][j][p] != undefined) { aDetail.push(returning[i][j][p].toString()); } } case "length" : var total = returning[i][j]; } } } } var tot= aDetail.length; //push each array slot into the string "Detailing" to form xml string for (var i = 1; i<tot; ++i) { Detailing += aDetail[i]; } aDetail.splice(0); //now send xml string to client clientNow.call("forcast",Detailing); } // if Above fails provide error forcast.onFault = function(fault){ trace( "fault->"+fault.faultstring ); clientNow.call("failed",fault.faultstring); }}

Where to go from here

This simple example should provide you with a better idea of the web services limitations that you will encounter. Having taken the time to explore the possibilities,however,you can see that when you use Flash Media Server 2,you have the freedom to interface with not only any language but with any result set as well.

For more information,check out the following resources for various technologies:

You may also wish to read up on?XML-RPC,a "spec and set of implementations that allow software running on disparate operating systems,running in different environments to make procedure calls over the Internet."

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读