The Linux system provides powerful and reliable network services, and management programs manage the services. For example, we are familiar with Web, FTP, and email, which can be run independently or called by the daemon inetd and run very well. But we can't just stay amazed. The following is an example of two service programs and one customer program, which describes how the communication between the service program and the customer program. In addition, you need to edit some configuration files so that the service program can accept the Service Management Program Management.
The two service programs have the same functions, but one is an independent service program and the other is a service program called by inetd. These are two types of TCP/IP network services. Here, the two programs are put together to compare the program structure and running mode. Both service programs are successfully debugged on Red Hat Linux 7.1 and turbolinux 7.0.
Independent Server
TCP and UDP are two major TCP/IP data transmission modes. The set of interfaces is the mechanism for establishing Server Client Connections. First, we will introduce the process of establishing communication between them, and then give a TCP Service program example.
1. TCP interface communication mode
For the TCP server, the service program first calls the function socket () of the Set interface, and then calls the BIND () function of binding the service IP address and protocol port number (). After the binding is successful, call the passive listener function listen () to wait for the client to connect, call the access request function accept (), and block the arrival of the Client Connection Request, this function gets the Client IP address and protocol port number.
For the tcp client, after the client starts the program, it calls the socket () interface function and then calls the connection function connect (). This function establishes a connection with the server through three handshakes.
After the server establishes a connection with the client, you can use the read () and write () functions to send and receive data. After the data exchange is complete, the close set interface function close () is called to delete the set interface. The TCP interface communication mode is shown in Figure 1.
Figure 1 tcp interface communication mode
2. UDP interface communication mode
The difference between UDP and TCP is that no connection is required. The server is started first, and then waits for user requests. After the client starts, it directly requests the service from the server. After receiving the request, the server gives a response.
On the UDP server, the service program first calls the socket () function of the Set interface, and then calls the BIND () function of the binding IP address and protocol port number (). Then, call the recvfrom () function to receive customer data and call sendto () to send data to the customer.
For UDP clients, after the client program starts, it calls the socket () function of the Set interface, then calls sendto () to send data to the server, and CALLS recvfrom () to receive server data.
After the data exchange between the two parties is successful, they call the close set interface function close () to close the set interface. See figure 2.
Figure 2 UDP interface communication mode
The following is an example of an independent service program. This program is simple, but has the same structure as the complex program.
// Program name: Server. c
// Function: the server reads one character from the client and returns the character following the character to the client.
// Server port 9000
# Include "sys/types. H"
# Include "sys/socket. H"
# Include "stdio. H"
# Include "netinet/in. H"
# Include "ARPA/inet. H"
# Include "unistd. H"
Int main ()
{
Int PID; // used to store fork () execution results
Int server_sockfd, client_sockfd; // used for server and client socket interface Descriptor
Int bind_flag, listen_flag; // used to store BIND () and listen () execution results
Int server_address_length, client_address_length; // serves as the Server Client address length variable.
Struct sockaddr_in server_address; // serves as the server address structure variable (including the address and port)
Struct sockaddr_in client_address; // serves as the client address structure variable (including the address and port)
If (pid = fork ())! = 0) // use fork () to generate a new process
Exit (0 );
Setsid (); // The program that starts with a sub-process
Function socket (): Creates a set of interfaces. If it is successful, the set of interface descriptors are returned.
Server_sockfd = socket (af_inet, sock_stream, 0 );
If (server_sockfd <0)
{
Printf ("socket error/N ");
Exit (1 );
}
Server_address.sin_family = af_inet;
The htonl () function is used to convert 32-bit host bytes to network bytes. The inaddr_any parameter indicates any IP address.
Server_address.sin_addr.s_addr = htonl (inaddr_any );
The htons () function is used to convert 16-bit host bytes to the network byte sequence. The parameter is the bound port number. You can modify the parameter according to the environment, the purpose is not to conflict with other service ports.
Server_address.sin_port = htons (9000 );
Server_address_length = sizeof (server_address );
BIND () is used to bind the local address and service port number. If the call is successful, the return value is 0.
Bind_flag = BIND (server_sockfd ,/
(Struct sockaddr *) & server_address ,/
Server_address_length );
If (bind_flag <0)
{
Printf ("BIND error/N ");
Exit (1 );
}
The listen () function specifies the queue length of the server and passively waits for the client to connect. If the call succeeds, the return value is 0.
Listen_flag = listen (server_sockfd, 5 );
If (listen_flag <0)
{
Printf ("Listen error/N ");
Exit (1 );
}
While (1)
{
Char ch;
The function accept () waits for and obtains user requests, creates a new set of interfaces for each new connection request, and returns the new set of interface descriptors after successful calls.
Client_sockfd = accept (server_sockfd ,/
(Struct sockaddr *) & client_address ,/
& Client_address_length );
The read () and write () functions are used to transmit data between the server and the client. The number of bytes read and write are returned after successful calls.
The close () function is used to close a set of interfaces after the program uses a set of interfaces. If the call succeeds, the return value is 0. The parameter here is the client_sockfd descriptor of the Set interface created by accept.
Read (client_sockfd, & Ch, 1 );
Printf ("cli_ch = % C", CH );
Ch ++;
Write (client_sockfd, & Ch, 1 );
Close (client_sockfd );
}
}
After the program is completed, you can use the command to compile it. Enter "gcc-O Server server. c" in the command line to compile server. c into an executable program server. Then the client program can be used for testing. Run "./Server" on the command line to start the service program and run "netstat-Na" to check whether the service port of the server is available. If yes, run the client program "./client ". However, this is only a manual start method. The following describes how to use the service management program to manage the server program. As long as the script is put into the service program under the/etc/rc. d/init. d directory, it can be read by the service program. Run "Touch server" on the command line to create the file server and change the file attribute to executable. The service name cannot be seen in the hypervisor. The script file must have some structure to be considered as a service script by the hypervisor.
To reduce the workload, copy the httpd script under/etc/rc. d/init. d, name it server, and edit it.
(1) Run "CP httpd server ".
(2) Use the text editor VI (Other Editors can also) to open the server and enter the editing status. First, replace httpd with the string server. Find the daemon server line. If the program is written in the path directory of the variable, you do not need to modify this line. If you put the service program in another directory, you need to write the full path of the service. For example, the program must be written as Daemon/root/server in the/root directory, and delete the line "RM-F/var/run/server. PID.
(3) Run "chmod 755 server" and set the server attribute to executable.
In this case, you can use tools such as chkconfig and ntsysv to add this new service program to the desired running level, and then test whether the client can communicate with the server.
Service program called by xinetd
In Linux, many services are started by the xinetd (inetd in earlier versions) super daemon server. In fact, all services based on TCP and UDP can be started using the super daemon, but they are not used when the service volume greatly affects the efficiency.
1. Establish a communication process based on the service started by xinetd
To compare with the independent server program, let's take a look at how the xinetd-dependent server is started.
(1) When xinetd is started, it reads files in the/etc/xinetd directory (earlier versions are/etc/inetd files ), create a set interface of the specified type for all services allowed to start according to the content, and put the set interface into the descriptor set in select.
(2) bind BIND () to each interface. The port number and other parameters are from the configuration file of each service in the/etc/xinetd directory.
(3) if it is a TCP interface, call the listen () function and wait for the user to connect. If it is a UDP interface, you do not need to call this function.
(4) After all sets of interfaces are created, call the select () function to check which sets of interfaces are active.
(5) If select () returns the TCP interface, it calls accept () to receive the connection. If it is UDP, you do not need to call this function.
(6) xinetd calls fork () to create a sub-process. The sub-process processes connection requests.
◆ The sub-process disables all other descriptors, leaving only the set of interface descriptors. This set of interface descriptor is the first set of interfaces for TCP that is returned by accept () and UDP. Then, the sub-process copies the set interface descriptor to 0, 1, and 2 three consecutive DUP () functions, which correspond to the standard input, standard output, and standard error output respectively, and disable the set interface descriptor.
◆ View users in files under/etc/xinetd in a sub-process. If the user is not a root user, use the setuid and setgid commands to change the user ID and group ID to the user specified in the file.
(7) For TCP interfaces, the parent process needs to close the connected interfaces after communication with the user. The parent process is in the select () status again, waiting for the next readable interface.
Finally, call the specified external service program in the configuration file. After the external program is started, information can be transmitted with the user.
2. Compile special service programs for xinetd
In addition to independent service programs that can be started by xinetd, you can also write special programs for xinetd. The example program has the same function as server. C above. However, there is a big difference between the two programs. The code in this example is only equivalent to the data transmitted above. We also set the program name as server. C, so it cannot be placed in the same directory. The same name is only used to compare with the above program.
# Include "unistd. H"
Int main ()
{
Char ch;
Read (0, & Ch, 1 );
Ch ++;
Write (1, & Ch, 1 );
}
Compile the program into an executable file and make some settings to be started by xinetd. Do not start the service with the independent service provider server. Because the client program is relatively simple to write, it accesses a fixed port and the server is set to the same port number.
(1) edit the/etc/services file and add a record at the end of the row:
Server 9000/tcp
(2) write the file server in the/etc/xinetd. d directory with the following content:
Service Server
{
Disable = No
Socket_type = stream
Protocol = TCP
Wait = No
User = root
Server =/home/test/server (set to the directory where your program is located)
}
If an earlier version is used, add the following lines to the/etc/inetd. conf file:
Server TCP Nowait root/path/to/yourdirectory/Server
(3) run/etc/rc. d/initd. d/xinetd restart to restart the xinetd server. In earlier versions, run/etc/rc. d/initd. d/inetd restart to restart inetd.
(4) Run netstat-An to check whether the port number is used by the server program. If yes, use the following client program for testing.
Client Program
The following is a brief introduction to client functions.
// Program name client. c
/* Function: enter a character from the customer's console, send the character to the server, and display the character returned by the server */
# Include "sys/types. H"
# Include "sys/socket. H"
# Include "stdio. H"
# Include "netinet/in. H"
# Include "ARPA/inet. H"
# Include "unistd. H"
Int main ()
{
Int sockfd ;//
Int address_len;
Int connect_flag;
Struct sockaddr_in address;
Int connect_result;
Char client_ch, server_ch;
The socket () function is used to create a set of interfaces and return the set of interface descriptors after successful creation.
Sockfd = socket (af_inet, sock_stream, 0 );
If (sockfd <0)
{
Printf ("sockfd error/N ");
}
Address. sin_family = af_inet;
Address. sin_addr.s_addr = inet_addr ("192.168.0.1");/* the reader changes the address of the server according to his environment */
Address. sin_port = htons (9000 );
Address_len = sizeof (Address );
Function connect () is used to establish an active connection with the server. The return value for successful calls is 0.
Connect_flag = connect (sockfd, (struct sockaddr *) & Address, address_len );
If (connect_flag =-1)
{
Perror ("client ");
Exit (1 );
}
Printf ("input a character :");
The scanf () function is used to input a character from the console and store the character to the client_ch address. The write () and read () functions are used to transmit data. The printf () function displays the characters returned by the server on the client screen. Function close () to close the set of interfaces.
Scanf ("% C", & client_ch );
Write (sockfd, & client_ch, 1 );
Read (sockfd, & server_ch, 1 );
Printf ("character from server: % C/N", server_ch );
Close (sockfd );
Exit (0 );
}
Run the command "gcc-O Client client. c" to compile client. c into a client. Run "./client" and enter a character at the program prompt to see the characters returned by the server.
The above is just a simple example. Generally, the service programs we see are far more complex than them, and many of them are multi-protocol service programs or multi-protocol multi-service programs. Multi-Protocol service programs create TCP and UDP interfaces for service in main () respectively. The advantage of writing corresponding programs for each service is that it is easy to control, but in this way, each service starts two servers, and their algorithm responses are the same, which consumes unnecessary resources, troubleshooting is also difficult. A multi-service is a program that integrates different services. An array is used to represent services. Each item in the array represents a service under a certain protocol, in this way, it is easy to expand the service functions of the program.