Socket programming principles

Source: Internet
Author: User
Tags file transfer protocol

 


1. Problem Introduction
The I/O command set of UNIX systems evolved from COMMANDS IN Maltics and earlier systems, the mode is open-write-read-close ). When a user process performs an I/O operation, it first calls "open" to obtain the right to use the specified file or device, and returns an integer number called a file descriptor, to describe the process of I/O operations on open files or devices. The user process then calls "read/write" multiple times to transmit data. After all the transmission operations are completed, the user process closes the call and notifies the operating system that an object has been used.

When the TCP/IP protocol is integrated into the UNIX kernel, it is equivalent to introducing a new type of I/O operation in the UNIX system. The interaction between UNIX user processes and network protocols is much more complex than that between user processes and traditional I/O devices. First, how do we establish a connection between two process keys on the same machine? Second, there are multiple network protocols. How can we establish a general mechanism to support multiple protocols? These are all problems to be solved on the Web application programming interface.

In UNIX systems, there are two types of network application programming interfaces: socket of unix bsd and TLI of UNIX System V. Sun adopts a unix bsd operating system that supports TCP/IP, which makes TCP/IP applications more advanced. Its Network Application Programming Interface-socket) it has been widely used in network software and has been introduced into the computer operating system DOS and Windows systems to become a powerful tool for developing network application software. This chapter will discuss this issue in detail.

2 Basic concepts of socket programming
Before using socket programming, you must first establish the following concepts.

2.1 inter-network process Communication
The concept of Process Communication was initially derived from a standalone system. Since each process runs within its own address range, the operating system provides corresponding facilities for Process Communication to ensure that two processes communicate with each other in a mutually independent and coordinated manner, for example, pipe, named pipe, signal, message, and shared memory in UNIX BSD) and semaphores (semaphore), but they are only used for communication between local processes. Inter-network process Communication solves the problem of inter-process communication between different hosts (Process Communication on the same machine can be considered as a special case ). To solve this problem, we must first solve the problem of inter-network process identification. Unique process IDs are available for different processes on the same host. However, in a network environment, the process numbers assigned by each host cannot uniquely identify the process. For example, host A is assigned to process number 5, and process number 5 can also exist on host B. Therefore, the "process number 5" statement is meaningless.

The operating system supports a large number of network protocols. Different protocols work in different ways and have different address formats. Therefore, inter-network process communication must solve the problem of multi-protocol identification.

To solve the above problem, the TCP/IP Protocol introduces the following concepts.


Port

The communication port that can be named and addressable in the network is a resource that can be allocated by the operating system.

According to the description of the OSI Layer-7 protocol, the main difference between the transport layer and the network layer is that the transport layer provides process communication capabilities. In this sense, the final address of network communication is not only the host address, but also an identifier that can describe the process. To this end, the TCP/IP protocol puts forward the concept of protocol port (port), which is used to identify the communication process.

A port is an abstract software structure (including some data structures and I/O buffers ). After an application (process) establishes a binding with a port through a system call, the data transmitted by the transport layer to the port is received by the corresponding process, the data sent by the corresponding process to the transport layer is output through this port. In the implementation of the TCP/IP protocol, the client performs similar I/O operations according to the discipline. A process obtains a port, which is equivalent to obtaining a local unique I/O file, it can be accessed using common read/write primitives.

Similar to file descriptors, each port has an integer identifier called port number, which is used to distinguish different ports. Because the TCP and UDP protocols of the TCP/IP transport layer are completely independent software modules, their respective port numbers are also independent of each other. For example, TCP has a port 255, UDP can also have port 255, which does not conflict with each other.

Port number allocation is an important issue. There are two basic allocation modes: the first is global allocation, which is a centralized control mode. A recognized central organization uniformly allocates the results according to user needs and publishes them to the public. The second is local allocation, also known as dynamic connection. When a process needs to access the transport layer service, it applies to the local operating system. The operating system returns a unique local port number, the process then associates itself with the port number through appropriate system calls (bundled ). The above two methods are integrated in TCP/IP Port number allocation. TCP/IP divides the port number into two parts. A small number of reserved ports are allocated to the service process globally. Therefore, each standard server has a globally recognized port (well-known port), even if the key discipline is the same as that on the machine. The remaining ports are free ports and allocated locally. Both TCP and UDP stipulate that port numbers smaller than 256 can be reserved.


Address

The two processes that communicate in the network communicate with each other on the same machine. In an interconnected network, the two machines may be in the same network, and these networks are connected through network interconnection devices (gateways, bridges, routers, etc. Therefore, three levels of addressing are required:

1. A host can be connected to multiple networks. A specific network address must be specified;

2. Each host on the network should have a unique address;

3. Each process on each host should have a unique identifier on the host.

Generally, host addresses are composed of network IDs and Host IDS, which are expressed in 32-bit integer values in TCP/IP protocol. Both TCP and UDP use 16-bit port numbers to identify user processes.




Network byte sequence

Different computers store multi-byte values in different order. Some machines store low-bit bytes at the starting address (low-cost first), and some store high-bit bytes (high-price first ). To ensure data correctness, the network byte sequence must be specified in the network protocol. The TCP/IP protocol uses the high-price prefix format of 16-bit integers and 32-bit integers, which are included in the header file.


Connection

The communication link between two processes is called a connection. The connection in the discipline shows a buffer zone and a set of Protocol mechanisms, and the reliability is higher than that without connection.


Semi-correlation

To sum up, a triple in the network can uniquely identify a process in the world:

(Protocol, local address, local port number)

Such a triple is called half-association, which specifies each half of the join.


Full correlation

A complete inter-network process communication must be composed of two processes and can only use the same high-level protocol. That is to say, it is impossible for one end of the communication to use the TCP protocol, while the other end to use the UDP protocol. Therefore, a complete inter-network communication requires a quintuple:

(Protocol, local address, local port number, remote address, and remote port number)

Such a quintuple is called association, that is, two half-correlation protocols can be combined into an appropriate correlation, or completely specify to form a connection.


2.2 service methods
In the network hierarchy, each layer is strictly one-way dependent, and the division of labor and collaboration at each layer are concentrated on the interface between different levels of discipline and discipline. "Service" is an abstract concept that describes the relationship between quantitative disciplines, that is, a group of operations provided by each layer on the network to the upper layer. The lower layer is the service provider, and the upper layer is the user requesting the service. A service is expressed as a primitive, such as a system call or a library function. System calling is a service primitive provided by the operating system kernel to network applications or high-level protocols. The n layer in the network always provides more complete services to the n + 1 layer than the n-1 layer. Otherwise, the n layer has no value.

In OSI terminology, the network layer and its lower layers are also called the Communication Subnet. Only point-to-point communication is provided, and there is no concept of a program or process. The Transport Layer implements "end-to-end" communication, introduces the concept of inter-network process communication, and also solves problems such as error control, traffic control, data sorting (packet sorting), and connection management, different service methods are provided for this purpose:


Connection Oriented (virtual circuit) or connectionless

Connection-oriented service is an abstraction of the telephone system service model. That is, each complete data transmission must be connected, connected, and terminated. During data transmission, each data group uses a connection ID instead of a destination address ). Essentially, a connection is a pipe, and the data sent and received are not only in the same order, but also in the same content. TCP provides connection-oriented virtual circuits.

The connectionless service is the abstraction of the postal system service. Each group carries a complete Destination Address and each group is transmitted independently in the system. The connectionless service does not guarantee the order of groups. It does not recover and retransmit group errors, and does not guarantee the transmission reliability. UDP provides the connectionless datagram service.

The following are examples of the two types of services and their applications:


Service Type
Service
Example

Connection-oriented
Reliable message stream

Reliable byte stream

Unreliable connection
File Transfer (FTP)

Remote Logon (Telnet)

Digital Voice

No connection
Unreliable Datagram

Validated Datagram

Request-Response
Email (E-mail)

Registered email

Network Database Query



Sequence

During network transmission, two consecutive packets may go through different paths in the end-end communication, so that the order of arrival at the destination may be different from that at the time of transmission. "Order" means that the order of received data is the same as that of sent data. TCP provides this service.


Error Control

A mechanism that ensures that the data received by the application is error-free. The method for checking errors is generally used to test the "check and (Checksum)" method. The method to ensure error-free transmission is that both parties adopt the validation response technology. TCP provides this service.


Flow Control

A mechanism for controlling the data transmission rate during data transmission to prevent data loss. TCP provides this service.


Byte stream

The byte stream mode only regards the transmitted packets as a byte sequence and does not provide any boundaries of the data stream. The TCP protocol provides the byte stream service.


Packets

The receiver needs to save the message boundary of the sender. UDP provides message service.


Full/half duplex

The data between the end and end is transmitted in both directions.


Cache/out-of-band data

In the byte stream service, because there is no message boundary, a user process can read or write any number of bytes at a certain time point. Cache is required to ensure correct transmission or use of a stream control protocol. However, for some special requirements, such as interactive applications, such cache needs to be canceled.

A type of information that you want to process in a timely manner without passing through the conventional transmission mode during data transmission, such as the UNIX system interrupt key (Delete or Control-c) control-s and Control-q are called out-of-band data. Logically, it seems that the user process uses an independent channel to transmit the data. This channel is associated with each connected stream. Because the implementation of out-of-band data in Berkeley Software Distribution is inconsistent with the Host Agreement specified in RFC 1122, to minimize the problems in interoperability, it is recommended that the application writer not use the out-of-band data unless it is required for interoperability with existing services.

2.3 customer/Server mode
In TCP/IP network applications, the main mode of interaction between two processes is the Client/Server model, that is, the customer sends a service request to the Server, after receiving the request, the server provides the corresponding service. The customer/Server mode is based on the following two aspects: first, the network is created because the hardware and software resources, computing power, and information in the network are not equal and need to be shared, thus, a host with many resources is created to provide services, and the customer request service with few resources is not equivalent. Second, inter-network process communication is completely asynchronous, and there is no parent-child relationship between processes that communicate with each other without sharing the memory buffer. Therefore, a mechanism is required to establish a connection between processes that want to communicate with each other, provides synchronization for the data exchange between the two, which is the TCP/IP of the Ji households/Server mode.

The customer/Server mode takes the active Request Method in the key discipline process:

First, the server must start and provide the corresponding services according to the request:

1. Open a channel and inform the local host that it is willing to receive customer requests at a recognized address (port, for example, FTP is 21;

2. Wait for the customer's request to reach the port;

3. Receive a duplicate service request, process the request, and send a response signal. To receive a concurrent service request, activate a new process to process the request (such as fork and exec in UNIX ). The new process processes this customer request and does not need to respond to other requests. After the service is completed, close the communication link between the new process and the customer and terminate the process.

4. Return step 2, waiting for another customer's request.

5. Disable the server


Customer:

1. Open a channel and connect to the specific port of the host where the server is located;

2. Send a service request message to the server, wait for and receive the response; continue to send the request

3. After the request ends, the communication channel is closed and terminated.


We can see from the process described above:

1. The role of the client and server processes is non-symmetric, so the encoding is different.

2. Service processes are generally initiated upon requests from Ji households. As long as the system is running, the service process persists until it is normal or forced to terminate.

2.4 socket type
TCP/IP socket provides the following three types of sockets.


Stream socket (SOCK_STREAM)

It provides a connection-oriented and reliable data transmission service, which allows you to send data without errors and duplicates, and receive data in the sending order. Internal traffic control to avoid data flow exceeding the limit. Data is considered as a byte stream with no length limit. The file transfer protocol (FTP) uses a streaming socket.


Datagram socket (SOCK_DGRAM)

Provides a connectionless service. Data packets are sent in the form of independent packets, and error-free guarantee is not provided,


Data may be lost or duplicated, and the receiving order is disordered. Network File System (NFS) uses a datagram socket.


Original socket (SOCK_RAW)

This interface allows direct access to lower-layer protocols, such as IP and ICMP. It is often used to verify new protocol implementations or access new devices configured in existing services.

3. Basic Socket System Call
To better illustrate the socket programming principles, the following describes how to call basic socket systems.

3.1 create socket ── socket ()
Before using a socket, an application must first have a socket. The system calls socket () to provide the application with the means to create a socket. The call format is as follows:

Socket pascal far socket (int af, int type, int protocol );

This call receives three parameters: af, type, and protocol. The af parameter specifies the region where the communication occurs. The address families supported by UNIX systems include AF_UNIX, AF_INET, and AF_NS. in DOS and WINDOWS, only AF_INET is supported, which is the Internet region. Therefore, the address family is the same as the protocol family. The type parameter describes the type of the socket to be created. The protocol Parameter indicates the specific protocol used by the socket. If the caller does not want to specify the protocol, the value is set to 0 and the default connection mode is used. Create a socket based on the three parameters, allocate the corresponding resources to it, and return an integer socket number. Therefore, the socket () System Call actually specifies the "protocol" dollar in the related quintuple.

For a detailed description of socket (), see 5.2.23.

3.2 specify the local address -- bind ()
After a socket is created with socket (), a namespace (address family) exists, but it is not named. Bind () associates the socket address (including the local host address and local port address) with the created socket number, that is, assign the name to the socket to specify the local semi-correlation. The call format is as follows:

Int pascal far bind (SOCKET s, const struct sockaddr FAR * name, int namelen );

The parameter s is the socket Descriptor (socket number) returned by the socket () call and not connected ). The parameter name is the local address (name) assigned to socket s. Its length is variable and the structure varies with the communication domain. Namelen indicates the name length.

If no error occurs, bind () returns 0. Otherwise, SOCKET_ERROR is returned.

The address plays an important role in establishing socket communication. As a Network Application Designer, you must have a clear understanding of the socket address structure. For example, unix bsd has a set of data structures that describe the socket address. The address structure using the TCP/IP protocol is:

Struct sockaddr_in {

Short sin_family;/* AF_INET */

U_short sin_port;/* 16-bit port number, network byte order */

Struct in_addr sin_addr;/* 32-bit IP address, network byte order */

Char sin_zero [8];/* Reserved */

}

For more information about bind (), see 5.2.2.

3.3 establish a socket connection -- connect () and accept ()
These two system calls are used to complete a complete related establishment, and connect () is used to establish a connection. A connectionless socket process can also call connect (), but there is no actual Packet Exchange Between processes. The call will be directly returned from the local operating system. The advantage of this is that the programmer does not need to specify the destination address for each data, and if a datagram is received, the destination port does not establish a "connection" with any socket ", this allows you to determine whether the client depends on discipline and discipline. And accept () is used to make the server wait for the actual connection from a customer process.

The call format of connect () is as follows:

Int pascal far connect (SOCKET s, const struct sockaddr FAR * name, int namelen );

The parameter s is the local socket descriptor to establish a connection. The parameter name indicates the pointer indicating the structure of the socket address of the other party. The length of the socket address of the other party is described by namelen.

If no error occurs, connect () returns 0. Otherwise, SOCKET_ERROR is returned. In the connection-oriented protocol, this call causes the actual connection between the local system and the external system.

Because the address family is always included in the first two bytes of the socket address structure, and is related to a protocol family through socket () calls. Therefore, the bind () and connect () protocols are not required as parameters.

For more information about connect (), see 5.2.4.

The call format of accept () is as follows:

Socket pascal far accept (SOCKET s, struct sockaddr FAR * addr, int FAR * addrlen );

The parameter s is the local socket descriptor. You must call listen () before using the parameter called by accept (). The addr pointer to the client's socket address structure to receive the address of the connected object. The exact addr format is determined by the address family created at the socket creation. Addrlen is the length (in bytes) of the client socket address ). If no error occurs, accept () returns a SOCKET type value, indicating the descriptor of the received SOCKET. Otherwise, the returned value is INVALID_SOCKET.

Accept () is used for connecting servers. The addr and addrlen parameters store the customer's address information. Before the call, the addr parameter points to an address structure with an empty initial value, while the initial value of addrlen is 0. After the accept () is called, the server waits for the customer connection request to be received from the socket number s, and the connection request is sent by the customer's connect () call. When a connection request arrives, the accept () call puts the first client socket address and length in the request connection queue into addr and addrlen, create a new socket number with the same features as s. The new socket can be used to process concurrent requests from the server.

For more information about accept (), see 5.2.1.

Four socket system calls, socket (), bind (), connect (), accept (), can complete a fully quintuple-related establishment. Socket () specifies the Protocol element in the quintuple. Its usage has nothing to do with whether it is a customer or server or connection-oriented. Bind () specifies the Local Binary In the quintuple, that is, the address and port number of the local host. Its usage is related to whether connection is oriented, bind () must be called. If bind () is used, bind () can be called without using connect. If no connection is used, the customer must use bind () to obtain a unique address.

The above discussion is only for the customer/Server mode. In fact, the use of sockets is very flexible. the only principle to be followed is that a complete correlation must be established before the process communication.

3.4 listener connection-listen ()
This call is intended for connection servers, indicating that it is willing to receive connections. Listen () must be called before accept (). The call format is as follows:

Int pascal far listen (SOCKET s, int backlog );

The parameter s identifies a locally established, unconnected socket number, and the server is willing to receive requests from it. Backlog indicates the maximum length of the Request connection queue. It is used to limit the number of requests in the queue. Currently, the maximum value is 5. If no error occurs, listen () returns 0. Otherwise, it returns SOCKET_ERROR.

During the execution of the call, listen () can complete the required connection for the socket s without calling bind () and establish a request connection queue with the length of backlog.

Calling listen () is the third step in the four steps in which the server receives a connection request. It allocates a stream socket when socket () is called, and CALLS bind () after giving s a name, and must be called before accept.

For more information about listen (), see 5.2.13.

As mentioned in section 2.3, there are two types of services in the key Ji household/Server mode: duplicate services and concurrent services. The accept () call provides great convenience for implementing concurrent services, because it returns a new socket number. Its typical structure is:

Int initsockid, newsockid;

If (initsockid = socket (.) <0)

Error ("can't create socket ");

If (bind (initsockid,.) <0)

Error ("bind error ");

If (listen (initsockid, 5) <0)

Error ("listen error ");

For (;{

Newsockid = accept (initsockid,)/* blocking */

If (newsockid <0)

Error ("accept error");

If (fork () = 0) {/* sub-process */

Closesocket (initsockid );

Do (newsockid);/* process the request */

Exit (0 );

}

Closesocket (newsockid);/* parent process */

}


The execution result of this program is that newsockid is related to the establishment of the customer's socket. After the sub-process is started, the initsockid of the inherited master server is disabled and the new newsockid is used to communicate with the customer. The initsockid of the master server can continue to wait for new client connection requests. In Unix and other preemptive multi-task systems, multiple processes can be simultaneously scheduled. Therefore, the use of concurrent servers allows the server process to have multiple sub-processes and different client programs to connect and communicate at the same time. In the key Ji household program, the server can concurrently process requests from multiple clients, which is the reason for the name of the concurrent server.

The connection server can also be a duplicate server. Its structure is as follows:

Int initsockid, newsockid;

If (initsockid = socket (.) <0)

Error ("can't create socket ");

If (bind (initsockid,.) <0)

Error ("bind error ");

If (listen (initsockid, 5) <0)

Error ("listen error ");

For (;{

Newsockid = accept (initsockid,)/* blocking */

If (newsockid <0)

Error ("accept error");

Do (newsockid);/* process the request */

Closesocket (newsockid );

}

A duplicate server can only establish a connection with one customer program at a time. It processes Multiple customer programs repeatedly in a circular manner, so it is called a duplicate server. Concurrent servers and repeated servers have their own advantages and disadvantages: Concurrent servers can improve the response speed of customers' programs, but they increase the overhead of System Scheduling. Duplicate servers are the opposite, therefore, when you decide whether to use a concurrent server or duplicate server, you must test the network according to the actual situation of the application.

3.5 data transmission-send () and recv ()
After a connection is established, data can be transmitted. Common system calls include send () and recv ().

The send () call is used to send output data on the connected datagram or stream socket specified by the key discipline s. The format is as follows:

Int pascal far send (SOCKET s, const char FAR * buf, int len, int flags );

The parameter s is the descriptor of the connected local socket. The buf pointer to a buffer with sent data. Its length is specified by len. Flags specifies the transmission control mode, such as whether to send out-of-band data. If no error occurs, send () returns the total number of bytes sent. Otherwise, it returns SOCKET_ERROR.

For a detailed description of send (), see 5.2.19.

The recv () call is used to receive input data on the connected datagram or stream socket specified by the key discipline s. The format is as follows:

Int pascal far recv (SOCKET s, char FAR * buf, int len, int flags );

The parameter s is the connected socket descriptor. The buf pointer to the buffer for receiving input data. Its length is specified by len. Flags specifies the transmission control mode, such as whether to receive out-of-band data. If no error occurs, recv () returns the total number of bytes received. If the connection is closed, 0 is returned. Otherwise, it returns SOCKET_ERROR.

For a detailed description of recv (), see 5.2.16.

3.6 multiplexing of input/output-select ()
The select () call is used to detect the status of one or more sockets. For each socket, this call can request read, write, or error information. The socket set in the given Request status is indicated by an fd_set structure. This structure is updated to reflect the subset of sockets that meet specific conditions. At the same time, the select () call returns the number of sockets that meet the conditions. The call format is as follows:

Int pascal far select (int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * limit TFDs, const struct timeval FAR * timeout );

The nfds parameter indicates the value range of the socket descriptor to be checked. This variable is generally ignored.

The readfds parameter points to the pointer to the socket descriptor set for read detection. The caller wants to read data from it. The writefds parameter points to the pointer to the socket descriptor set for write detection. Exceptfds indicates the pointer to the socket descriptor set to detect for errors. Timeout points to the maximum waiting time of the select () function. If it is set to NULL, the operation is blocked. Select () returns the total number of socket descriptors that have been prepared in the fd_set structure, or returns SOCKET_ERROR if an error occurs.

For a detailed description of select (), see 5.2.18.

3.7 close socket ── closesocket ()
Closesocket () closes socket s and releases the resources allocated to the socket. If s involves an open TCP connection, the connection is released. Closesocket () is called in the following format:

Bool pascal far closesocket (SOCKET s );

Socket descriptor to be disabled by parameter s. If no error occurs, closesocket () returns 0. Otherwise, SOCKET_ERROR is returned.

For details about closesocket (), see 5.2.3.

2.4 typical SOCKET call process example
As mentioned above, TCP/IP applications generally adopt the customer/Server mode. Therefore, in actual applications, there must be two processes: the customer and the server, and the server must be started first, the system call sequence is shown below.

Connection-oriented protocol (such as TCP) Socket System Call 2.1 is shown in:

The server must be started first until it completes the accept () call and enters the waiting state before receiving the customer request. If the customer starts before this, connect () will return the error code and the connection fails.


Figure 2.1 Sequence of connection-oriented socket system calls


The SOCKET call 2.2 Without connection protocol is shown in:
Figure 2.2 sequence of SOCKET call without connection protocol

If the server is not connected, you must start the service first. Otherwise, the service process cannot be passed in the client request. No connected customers do not call connect (). Therefore, before sending data, the customer and the server have not yet established a complete correlation, but each has established a semi-correlation through socket () and bind. When sending data, the sender also needs to specify the receiver socket number in addition to the local socket number, so as to dynamically establish full correlation during the data sending and receiving process.



Instance

This instance uses the connection-oriented Client/Server mode. The process is as follows: 2.3:


Figure 2.3 connection-oriented application Flowchart

Server program:


/* File Name: streams. c */

# Include

# Include

# Define TRUE 1

/* This Program establishes a socket and starts an infinite loop. Every time it receives a connection through a loop, a message is printed. When the connection is disconnected or the termination information is received, the connection ends and the program receives a new connection. The command line format is: streams */


Main ()

{

Int sock, length;

Struct sockaddr_in server;

Struct sockaddr tcpaddr;

Int msgsock;

Char buf [1024];

Int rval, len;


/* Create a socket */

Sock = socket (AF_INET, SOCK_STREAM, 0 );

If (sock <0 ){

Perror ("opening stream socket ");

Exit (1 );

}


/* Use any port to name the socket */

Server. sin_family = AF_INET;

Server. sin_port = INADDR_ANY;

If (bind (sock, (struct sockaddr *) & server, sizeof (server) <0 ){

Perror ("binding stream socket ");

Exit (1 );

}


/* Find the specified port number and print it out */

Length = sizeof (server );

If (getsockname (sock, (struct sockaddr *) & server, & length) <0 ){

Perror ("getting socket name ");

Exit (1 );

}

Printf ("socket port # % d \ n", ntohs (server. sin_port ));


/* Start receiving connections */

Listen (sock, 5 );

Len = sizeof (struct sockaddr );

Do {

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.