Wonderful ISAPI Programming

Source: Internet
Author: User
Tags printable characters
I used to develop some ISAPI programs. I have been searching for the Internet for a long time and have not been fully written. I did not write much in the book in the bookstore. So after two months of exploration, finally, I made some things. For a long time, I have always wanted to write an ISAPI article, but I have never had time. Now I am free to write down what I have learned recently.
I want to write the following ideas:
1. Introduction to ISAPI
2. A simple ISAPI Program
3. ISAPI for customer/server interaction
4. ISAPI database operations
5. Use ISAPI for Network Data Transmission
6. ISAPI data transmission Encryption
7. Advanced ISAPI network data transmission (Network big data packet transmission)
8. Summary

I. Introduction to ISAPI

The Common Gateway Interface CommonGatewayInterface (CGI) has long been widely used in the Internet as a standard for interactive Web applications. CGI scripts allow people to write simple applications in a variety of programming languages (such as Basic, C, Perl, Shell, and so on. These scripts run on the Web server and output the running results on the client's Web browser. Customer input is transmitted through environment variables or standard input devices. Then, CGI programs perform specific operations as needed and display them in the customer's browser in HTML format. This feature of CGI brings vitality to the Internet, and the construction of websites has changed from silence to enthusiastic girls. Over time, the once sensational Snow White is also getting tired.
In the long-term use, people still find a major drawback of CGI applications: low performance. Each time I request a CGE program, the CGI execution file (or the script interpreter) creates a new process for each request. For a site with a large amount of information, this undoubtedly adds a heavy burden to the server.
Over the years, ASP and JSP have been launched on the lively internet to improve security and server performance. However, their security and development tools are far less mature than VC, delphi and other successful tools, and as a programmer familiar with software programming, using ready-made development tools and existing resources to develop a website system is more handy.

ISAPI (Internet Server Aplication Programing Interfase) is a standard programming interface that is developed with programming tools and runs on the NT Service. Web developers can use it to compile interactive applications. ISAPI Expansion
The Extension application has the same CGI script functionality, but it has faster and more effective performance than CGI.
For applications written by ISAPI for Windows NT, Web users can activate the application by entering an HTML form (form) or clicking a link on the HTML page on the Web node. After the server obtains the information provided by the user, the activated ISAPI application processes the obtained information. Store the obtained information to the database based on the functions of the ISAPI application, or access the data in the database based on the obtained information, and then return the result to the client in the form of an HTML page.
The ISAPI application is compiled into a Dynamic link Library (DLL, Dynamic Linked Library), which is loaded into the memory at the startup of the WWW Service. It requires less system overhead and significantly outperforms CGI applications. Because each request does not start a separate process. If CGI is used as an interactive program, each request needs to start a separate process.

ISAPI has obvious performance advantages, but its debugging is not very good, and there are few development materials, which has always become a reason why developers are not preferred. In order to make more extensive use of ISAPI, this article is designed for developers to enter the development process more quickly.

Return

2. A simple ISAPI Program

New, Object, ISAPI Extension Wizard, the Object Name starts with FirstISAPI, OK, do not change anything in step 2, click Finshed to complete. Press F7 to put the generated DLL in the C: \ inetpub \ wwwroot \ firstisapi directory (do you need to teach me how to create a folder ?), Open your browser and enter http: // 127.0.0.1/firstisapi/FirstISAPI. dll in the address bar.
OK
We can immediately see the following content:
This default message was produced by the Internet Server DLL Wizard. Edit your CFirstISAPIExtension: Default () implementation to change it.
Have you seen it?
If you see the English string above, your server can be used. If you see a File Download Dialog Box, don't cry! It indicates that your server has not been properly configured. I will teach you step by step. Don't miss this opportunity if you will use it!
Start, program, administrative tool, and Internet service manager. Open the left Tree, find firstisapi under the default Web site, right-click it, and click Properties. In the execution permission drop-down list, select the script and executable program. Do not change anything. (If you think it is fun, do it. But if the server configuration is poor, don't blame me for not making a "Declaration" in advance :)"). what should we do next? Forget, wait! Oh, by the way, click OK. If not, you have a Chinese version. Click OK!
Okay, http: // 127.0.0.1/firstisapi/FirstISAPI. dll --------------------- >>>

This default message was produced by the Internet Server DLL Wizard. Edit your CFirstISAPIExtension: Default () implementation to change it.
This time, right?
Not yet?
Forget it. Don't learn ISAPI. It's so annoying. I'm tired of it if you don't bother me!
(I thought, this kind of possibility still exists. I am still here for the end, so that you may not scold me again. Okay, open the optical drive and put the 2000 disk into it, why? Add components and reinstall your INTERNET service !......)
Won't this happen?
No?
Oicq608@163.com
OICQ: 67406204
Http://www.ourcode.net/
Contact me. I will help you !!!~~~~~~~~~

In this way, our first ISAPI is made. You can rest assured that I will be an ISAPI... --------- fart! This is also called meeting?

By the way, I forgot my WIN98 friend. Sorry, have you installed PWS?
No?
Install one!
Other things are similar to those in 2000. Don't I teach them?
:):)

Return

Iii. ISAPI for customer/server interaction

Now we can build a simple ISAPI program, but it has not implemented any functions. After all, we have not added code to let it work!
Add a member function void Getdata (CHttpServerContext * pCtxt, char * data) in the response class like a general program. Then add it in BEGIN_PARSE_MAP (CFirstISAPIExtension, CHttpServer) and END_PARSE_MAP (response) add ON_PARSE_COMMAND (Getdata, CFirstISAPIExtension, ITS_PSTR) and ON_PARSE_COMMAND_PARAMS ("data ")
, As shown below:

BEGIN_PARSE_MAP (CFirstISAPIExtension, CHttpServer)
// TODO: insert your ON_PARSE_COMMAND () and
// ON_PARSE_COMMAND_PARAMS () here to hook up your commands.
// For example:
ON_PARSE_COMMAND (Getdata, CFirstISAPIExtension, ITS_PSTR)

ON_PARSE_COMMAND_PARAMS ("data ")
ON_PARSE_COMMAND (Default, CFirstISAPIExtension, ITS_EMPTY)
DEFAULT_PARSE_COMMAND (Default, CFirstISAPIExtension)
END_PARSE_MAP (CFirstISAPIExtension)

ON_PARSE_COMMAND and ON_PARSE_COMMAND_PARAMS are parameter ing macros. The first parameter Getdata of ON_PARSE_COMMAND is the function name for processing the event, and the second parameter CFirstISAPIExtension is the application subclass with CHttpServer as the parent class, the following parameters will be passed to the Getdata function parameter list. They can be: ITS_EMPTY: no data is available; ITS_PSTR: string; ITS_I2: short integer; ITS_I4: long integer; ITS_R4: float floating point count; ITS_R8: double Floating Point count. The number of parameters generally corresponds to the parameter parsed by ON_PARSE_COMMAND_PARAMS. Here we can assign an initial value to the data parameter. It is the actual value that is not passed in the browser. For example, data = www.ourcode.net. Here, data is the name of the parameter to be passed in the Getdata function.

With the above preparations, we can add the code below, because it is no different from normal programming, so we simply add a bit of code to see what we have done after half a day of work?

As follows:

Void CFirstISAPIExtension: Getdata (CHttpServerContext * pCtxt, char * data)
{

StartContent (pCtxt); // write the HTML file header
WriteTitle (pCtxt); // write the title
* PCtxt <_ T ("this is the data you submitted: <br> \ r \ n"); // send data to the browser
* PCtxt <data <"\ r \ n"; // write the last line break and press Enter.
EndContent (pCtxt)

}

CHttpServerContext * pCtxt is a server context mark, which is used to transmit data to the browser.
* PCtxt <the string is the HTML source code in the browser. Therefore, you can set "this is the data you submitted: <br> \ r \ n"
Change it to the HTML you want! :)

Are you sure you want to press F7 now? Haha, okay, F7. Immediately press FirstISAPI. dll Ctrl + C, Ctrl + V ........

"Unable to create or replace FirstISAPI: the specified file is being used by Windows", no way?

I will restart the computer. Who will teach it to load the memory! But you can also change the DLL name, or wait for a cigarette again!

The following ISAPI debugging article can be viewed by friends who do not like to restart their computers.
ISAPI is a part of IIS at runtime, and IIS runs as a service of NT. The debugging process is complicated because the VC ++ debugger cannot take over ISA When IIS is running. To solve this problem, Microsoft released IIS in two forms: as a service and as a separate executable program. In the latter case, we can control the server on the command line. Although this can solve the above problems and make the development process easier, it is very cumbersome to implement. Next we will introduce this process.

When the user is in debug mode, VC ++ (and IIS) runs under the user's account and permissions. Generally, most users are not allowed to have the relevant permissions for some work completed by IIS. Therefore, users (or their system administrators) need to do the following:

On the desktop, select start \ Program \ management tool (public) \ domain user manager to open the domain user manager;
Select "User Permissions" from the "Rules" menu ";
Select the "show Advanced User Permissions" check box;
In the "permission" drop-down list, select "operate as operating system ";
Select the "add" button to get the "add user and group" dialog box, select the "show user" button, and select the account used by the user in the "name" list, then select the Add button;
Select "OK;
Repeat the preceding steps for the "Generate Security Audit" permission.

To make these settings take effect, you must log out and then log back.
IIS contains three services: FTPPublishing Service, GopherPublishingService, and WorldWideWeb. Because the debugger needs to run IIS on the command line, all three services must be stopped. This can be achieved through the "service" program in the "control panel" or the "Internet Service Manager" of IIS. If you need a lot of debugging work, we recommend that you disable IIS services and disable them from starting automatically through the "service" program in the "control panel, this prevents you from shutting down services every time you start your computer.
Next, you must configure the project:
Select the Settings menu item from the Project menu;
Select the Debug panel and select General from the Category drop-down list;
Enter or search for the IIS execution file path in the Executablefordebugsession box (usually in WINNT \ system32 \ inetsrv \ inetinfo.exe );
Enter-ew3svc in the Programarguments box, as shown in Figure 3. Figure 3 Debug panel settings
Select the Link Panel;
Enter the path and file name of the compiled DLL in the Outputfilename box. This path must be located in the root directory of the Web server or a virtual target, so that the customer can access it through the URL. For example, the Directory of our Web server is c: \ InetPub \ wwwroot \ firstisapi. dll is placed in this directory, so that the customer can access it using the following URL:
Http: // 127.0.0.1/firstisapi. dll
If the user has not logged out to change the permission, proceed now and then log back.
In this case, our Server DLL is finished. Enter http: // 127.0.0.1/firstisapi. dll in the browser? Getdata & data = This is the information I sent to the server!

OK?

Here is the data you submitted:

This is the information I sent to the server!

OK!

What if we want to submit data to the server in form?

Save the following HTML source code as a firstisapi.htm file in the same directory as the DLL.

<Form method = "post" action = "firstisapi. dll? ">
<P align = "center"> </p>
<Input type = "hidden" name = "MfcISAPICommand" value = "Getdata">
<P align = "center"> data to be submitted: <input type = "text" name = "data" size = "20"> </p>
<P align = "center"> <input type = "submit" value = "submit"> </p> </form> </body>

Return

Iv. ISAPI database operations

We have defined a Getdata function. In this function, we have implemented the following function: send the data transmitted by the customer to the customer. What if we operate the database? In the same way, you only need to add the database operation code to your own defined functions to access the database. the input data is in the variable data and output to the client using * pCtxt to the browser.
Now let's create a database. You can select the database you use. It can be ACCESS, SQL Server, Sbase, etc. We just need to use the data source to operate on it, after creating a database, we will create a system data source (do not build a user data source? Why? Ask Bill Gates.) FirstODBC, use the following SQL statement to create a simple table.
Table: user information
Create table user_info (
Id int (4) not null,
Friend_id int (4) not null,
User_name varchar (30) not null,
User_sex varchar (2) not null,
Address varchar (20 ),
Age int (4 ),
Zip char (6 ),
Phone varchar (20 ))

With the data source, we can add code to query and modify databases.
As in the previous section, add a member function void Reg (CHttpServerContext * pCtxt, char * user_name, char * sex, char * address, int age, char * zip, in CFirstISAPIExtension, char * phone)
The parameters are user name, gender, address, age, zip code, and phone number. we want it to implement the function of writing the data submitted by the user through the form to the FirstODBC database. then, add ON_PARSE_COMMAND (Reg, iterator, ITS_PSTR its_its_i2 ITS_PSTR) between BEGIN_PARSE_MAP (latency, CHttpServer) and END_PARSE_MAP)
And ON_PARSE_COMMAND_PARAMS ("user_name sex address ='' age = 20 zip = ''phone = '')
, As shown below:

BEGIN_PARSE_MAP (CFirstISAPIExtension, CHttpServer)
// TODO: insert your ON_PARSE_COMMAND () and
// ON_PARSE_COMMAND_PARAMS () here to hook up your commands.
// For example:
ON_PARSE_COMMAND (Reg, CFirstISAPIExtension, ITS_PSTR ITS_I2 I
ITS_PSTR)
ON_PARSE_COMMAND_PARAMS ("user_name sex address age zip phone)
ON_PARSE_COMMAND (Getdata, CFirstISAPIExtension, ITS_PSTR)
ON_PARSE_COMMAND_PARAMS ("data ")
ON_PARSE_COMMAND (Default, CFirstISAPIExtension, ITS_EMPTY)
DEFAULT_PARSE_COMMAND (Default, CFirstISAPIExtension)
END_PARSE_MAP (CFirstISAPIExtension)

Next we define our own functions and perform database operations. Click FirstISAPI classes, New Class, Name: CUserSet, Base class: CRecordset --------------- OK, ODBC: FirstODBC, Table Name: user_info, OK.
(Check whether there is # include in stdafx. h first)

Void Reg (CHttpServerContext * pCtxt, char * user_name, char * sex, char * address, int age, char * zip, char * phone)

{// Open the source code of the database
StartContent (pCtxt); // print the <HTML> and <BODY> tags
WriteTitle (pCtxt); // print <TITLE>, "TITLE content", and </TITLE> tags.
CDatabase db;
If (! Db. Open (_ T ("FirstODBC"), // (system source name)
FALSE, // bExclusive
FALSE, // bReadOnly
_ T ("ODBC; UID = sa; PWD =;"), // lpszConnect (connection method to the database)
FALSE) {// bUseCursorLib
* PCtxt <"cocould not open database .";
Return;
}
CRecordset set (& db );
Try
{
Set. Open ();
}
Catch (CDBException * pEx)
{
* PCtxt <_ T ("Error Selecting from table :");
TCHAR szErrorMessage [1024];
If (pEx-> GetErrorMessage (szErrorMessage, sizeof (szErrorMessage )))
{
* PCtxt <szErrorMessage;
* PCtxt <_ T ("\ r \ n ");
}
Return;
}
Set. AddNew ();
Set. Edit ();
Set. m_id = 0;
Set. m_user_name = user_name;
Set. m_sex = sex;
Set. m_address = address;
Set. m_age = age;
Set. m_zip = zip;
Set. m_phone = phone;
Set. Update ();
Set. Close ();
Db. Close ();
* PCtxt <_ T ("You have successfully registered! \ R \ n ");
// Print </BODY> and </HTML> tags
EndContent (pCtxt );
}
Save the following HTML as reg.htm

<HTML>
<BODY>
<CENTER>
<Font color = '# ff0000'> <H3> enter your registration information below (including * Mandatory) </H3>
</FONT>
</CENTER>
<HR>
<CENTER>
<Form method = "post" action = "firstisapi. dll? ">
<P align = "center"> </p>
<Input type = "hidden" name = "MfcISAPICommand" value = "Reg">
<P align = "center"> name: <input type = "text" name = "user_name" size = "20"> </p>
<P align = "center"> gender:
<Select name = "sex" size = "1">
<Option selected value = "1"> male </option>
<Option value = "0"> female </option>
</Select> </p>
<P align = "center"> address: <input type = "text" name = "address" size = "20"> </p>
<P align = "center"> age: <input type = "text" name = "age" size = "20"> </p>
<P align = "center"> zip code: <input type = "text" name = "zip" size = "20"> </p>
<P align = "center"> Tel: <input type = "text" name = "phone" size = "20"> </p>
<P align = "center"> <input type = "submit" value = "submit"> </p> </form>
</Center>
</BODY>
</HTML>

Put it in the firstisapi directory ,.................. http: // 127.0.0.1/firstisapi/reg.htm enter your data in the browser form and submit it. Check your server database. With -----------, you have successfully registered !! I wanted to create another query program, but the time was too short. Let's just think about it. It's no different from the registration program. Just add a Chaxun (...).
OK That is all right!
There are still some imperfections in the program, that is, whether the user name has been registered and the maximum value of the ID has not yet been obtained. However, this is only to demonstrate how to operate the database, so I did not worry deeply, if you are interested, you can add this code.

Return

5. Use ISAPI for Network Data Transmission

The so-called network data transmission, simply put, is to transmit data from one computer to another computer on the network. speaking of data transmission, we are the most familiar with socket sockets. in UNIX and WINDOWS, it is always recognized as a transmission solution. after studying ISAPI, the author successfully implements network data transmission using ISAPI and effectively transfers data within the LAN firewall.
First, we need to establish an ISAPI program for receiving server data. in section 3 <ISAPI implements customer/server interaction>, we have created a Getdata (.. char * data) function, where data stores the data we transmit from the client. In this function, we can process it, such as writing files, write the database, and then send a receipt to the customer through * pCtxt. how to Write a database to a file is beyond the scope of this section.
In section 3, we send data to the server through the form browser. Here, we want to send data to the server through our client program. Add a member function in your program: BOOL SendData (char * ip, char * request, char * buffer, unsigned int bufferlen). The parameter ip address is the Server ip address, if it is a local call, input 127.0.0.1; request is the data to be sent to the server, which is finally received by Getdata () and stored in data for processing by the server handler; buffer stores the forward buffer zone for the server's return receipt, that is, * the data bufferlen returned by pCtxt is the length of the forward buffer zone. The SendData code is as follows:
BOOL SendData (char * ip, char * request, char * buffer, unsigned int bufferlen)
{
Int ret = 0;
CString URL;
URL = "http ://";
URL + = (CString) ip address;
URL + = "/firstisapi. dll? Getdata & data = ";
URL + = (CString) request;
//
// AfxMessageBox (URL );
CInternetSession session;
CInternetFile * cf;
//----------------
Try {
Cf = (CInternetFile *) session. OpenURL (URL );
}
Catch (CInternetException * Exp)
{
Char err [1024];
Exp-> GetErrorMessage (err, 1024, NULL );
AfxMessageBox (err );
Cf = NULL;
Exp-> Delete ();
}
If (cf ){
Ret = cf-> Read (buffer, bufferlen );
Cf-> Close ();
}
Session. Close ();
Return (ret );
}
In this way, we can call it in the program as follows:
Void CSassDlg: OnButton1 ()
{
// TODO: Add your control notification handler code here
CString ip = "127.0.0.1", data = "this is the data I want to send to the server", buffer;
BOOL B = SendData (char *) maid (ip), (char *) maid (data), buffer. GetBuffer (1204), 1024 );
If (B ){
MessageBox ("data sent successfully ");
}
}
In this way, we only need to pass the data to the server to the second parameter of SendData, and the server data will be received. What do you want to do.

Return

6. ISAPI data transmission Encryption

To improve the security and reliability of data transmission, we need to encrypt data before data transmission, But no matter which encryption algorithm, all encrypted data may contain "@ # $ % ^ & *-+" and non-printable characters, but when transmitted using the ISAPI method, after the ON_PARSE_COMMAND and ON_PARSE_COMMAND_PARAMS parameter ing macros are processed on the server, for example, "%, &" and other characters will be automatically converted or processed as separator characters, the data received by the server will be incorrect. In order to ensure the reliability of data transmission, I have studied many aspects and defined the following two functions, which are respectively used as the client's encrypted data before uploading and the server's decrypted data before processing.
Data processing functions before upload after client encryption:
Void code (char * buf, int len, char * outstr) // post-Encryption
{
CString str;
Int outstr_len;
Outstr_len = 0;
Char * tmp;
Tmp = new char [16];
Outstr [0] = 0;
For (int I = 0; I <len; I ++)
{
Tmp [0] = 0;
If (buf [I] = '%' | buf [I] = '&' | buf [I] = '! '| Buf [I] = '? '| Buf [I] =' + '| buf [I] =' \ '| buf [I] = '/')
{
Str. format ("% x", buf [I]);
Strcpy (tmp, str );
Outstr_len + = 3;
}
Else
{Tmp [0] = buf [I]; tmp [1] = 0; outstr_len ++ ;}
If (buf [I] = '$ ')
{Strcpy (tmp, "$"); outstr_len + = 2 ;}
If (buf [I] = 0)
{Strcpy (tmp, "$0"); outstr_len + = 2 ;}
Strcat (outstr, tmp );
}
Return;
}
Buf is the pointer to the incoming data Shard, len is the buf data length, and outbuf is the processed data storage shard. special characters such as "%, &, +" and 0 characters are processed during processing. In this way, after data is transferred to the server, it will be correct, then, the data is restored by the server processing function and decrypted.

The pre-decryption function after the server receives the data:
Int decode (char * buff, int len, char * outstr)
// Post-Upload
{
Int I, p;
Char v;
P = 0;
For (I = 0; I <len; I ++)
{
If (buff [I] = '$ ')
{
If (buff [I + 1] = '$ ')
{
V = '$ ';
}
Else
{
If (buff [I + 1] = '0 ')
V = 0;
}
I ++;
}
Else
{
V = buff [I];
}
Outstr [p] = v; p ++;
}
Return (p );
}
Here, buff is the pointer to the incoming data Shard, len is the buff data length, and outstr is the processed data storage shard.
Process:
Data Encryption --------> code function processing --------> the server receives data -------> decode for upload and post-processing -------> decryption

Return

VII. ISAPI network data transmission (Network big data packet transmission)

I tried to use the above method to transmit large data packets, but found that this method can only transmit less than 2 k data packets, which is undoubtedly a disadvantage. After extensive research, we found that this method uses the GET method to send data, and the operating system itself limits its data volume. Tests will be conducted later. If POST transmission is used, the size of the sent data packets will not be limited. The following section describes how to use the POST method to send data to the server.

BOOL PostData (char * ip, char * request, char * out_buf, int buf_len)
{
BOOL ret = FALSE;
Char * buffer, * buff, * out;
Buffer = new char [2048];
Int bb_len = strlen (request );
Buff = new char [bb_len];
Out = new char [bb_len + 1000];
CInternetSession session;
CHttpFile * pFile = NULL;
CHttpConnection * pConnection = NULL;

CString m_ip, SQL;
M_ip = (CString) ip;
// ------------------------------ Encrypt the request
Strcpy (buff, request );
For (int I = 0; I <bb_len; I ++ )//
Buff [I] = buff [I] ^ (char) (I + 0x56) % 255 );
Code (buff, bb_len, out); // pre-Upload
//-----------------------------------
SQL = (CString) out;
CString strHeaders = _ T ("Content-Type: application/x-www-form-urlencoded ");
CString str, strformData = _ T ("data = ");
StrformData + = SQL;
Try
{
PConnection =
Session. GetHttpConnection (m_ip );
PFile =
PConnection-> OpenRequest (CHttpConnection: HTTP_VERB_POST,
_ T ("/firstisapi. dll? Getdata "));
BOOL result = pFile-> SendRequest (strHeaders,
(LPVOID) (LPCTSTR) strformData, strformData. GetLength ());
DWORD dwRet;
PFile-> QueryInfoStatusCode (dwRet );
//--------------
If (dwRet = HTTP_STATUS_ OK)
{
Buf_len = pFile-> Read (buffer, 2048 );
Str = (CString) buffer;
Str = str. Left (buf_len );
Ret = TRUE;
}
Else
Str = "server processing error! ";
PFile-> Close ();
Delete pFile;
PConnection-> Close ();
Delete pConnection;
}
Catch (CInternetException * pEx)
{
TCHAR szErr [1024];
PEx-> GetErrorMessage (szErr, 1024 );
Str = szErr;
PEx-> Delete ();
}
Catch (...)
{
Str = "An error occurred while communicating with the server! ";
}

Session. Close ();
Strcpy (out_buf, str );
Buf_len = str. GetLength ();
MessageBox (NULL, str, "system prompt", MB_ OK );
Delete buffer;
Delete buff;
Delete out;
Return ret;
}
Here, the parameter ip address is the Server ip address. If it is a local call, 127.0.0.1 is passed in; request is the data to be sent to the server, which is finally received by Getdata () and stored in data for processing by the server handler; buffer stores the forward buffer zone for the server's return receipt, that is, * the data bufferlen returned by pCtxt is the length of the forward buffer zone.

In this way, we can send data larger than 2 K.

Return

VIII. Summary

It's just a simple task. There are still many mistakes. Please reply to me if you find any mistakes during use! Thank you!

This article can be freely reproduced without retaining the author's copyright.

Longfei mailbox

OurCode. Net

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.