First experience of server-side programming

Foreword:

In the previous article, I gave an example of a client code program. At that time, it sent a request to the Baidu server, and then the server returned data to the client. We are not very familiar with the programming of the server, so today we will learn about the server. Learn to program!

Client/server programming mode (c/s mode):

If you have been in contact with network programming friends, you should know this c/s model. It generally means:

  • The server is exposed to the network for a long time and waits for the client to connect (the way of exposure here is to disclose its own ip address, which is easy to suffer from malicious attacks, which will cause the server to be paralyzed, and normal clients cannot use it. !)
  • The client initiates a connection action and waits for the server to respond

The characteristics of this mode are as follows:

  • The server cannot actively connect to the client
  • The client can only connect to the server in a predefined way (the predefined way here refers to the communication protocol! The protocol is the rule for data exchange, and this rule is artificially defined!)

Let's take a look at the process steps and framework diagram of this server mode:

  • ready to connect to the network
  • bind port
  • Enter the port monitoring state (if there is a connection on this port, that is, you can get the connection of the client, then how to get it? Get it through the accept function, the return value of this function is the socket value that actually communicates with the client , which is fd (file descriptor))
  • waiting for connection

insert image description here

Related function api introduction:

  • Binding interface (bind the socket of the server to an address, the address here is not only the IP address, but also the port number!):
int bind(int sock, struct sockaddr *addr , socklen_t addlen);
  • Listening (the backlog parameter here indicates the length of the queue, which means that when multiple clients connect, they need to queue up, that is, another queue is formed! Popular understanding, this parameter indicates how many clients connect to the server .):
int listen(int sock, int backlog);
  • Receive (here mainly pay attention to the return value of this function, what he returns is a socket value for communicating with the client!):
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);

In-depth analysis of the server:

  • 1. The socket on the server side is only used for receiving and connecting, not for actual communication

  • 2. When a connection is received, the accept() function returns the socket that communicates with the client; here we can see that the socket is also divided into types, one is the socket that actually communicates, and the other is the socket that receives the connection

  • 3. The server socket is used to generate a socket for communication with the client

So through the understanding of the above three sentences, then you will have doubts in your heart, what exactly is a socket? How to understand it? In order to better understand the socket, we look for a breakthrough from the socket() function interface:

  • Socket means "plug-in board" in Chinese. Everyone must have used this plug-in board. It is the socket we usually use at home. This socket can power your computer and charge your mobile phone! Simply understand, this power strip can be used to charge different electrical appliances!

  • From the perspective of socket programming, the function of this socket() interface is also multifunctional; now we use this socket() interface to communicate on the Internet, so it can only communicate on the Internet? This is not necessarily the case, it can also communicate with a dedicated network, or even communicate between local processes; so the essence of the socket() interface is to provide communication capabilities; as for which aspect of communication, this can be decided by ourselves , this is similar to the power strip mentioned above, it can support different electrical equipment for charging!

So what is a socket? Mainly from the following three directions:

  • 1. From the outside, socket() is a "multifunctional" function. In our programming, just call it directly!
  • 2. What is the return value of socket()? The return value of the socket() function is a resource identifier for communication; here we can think about it, if we want to communicate, will it occupy the resources of the operating system? The answer is definitely that it will be occupied, so we need to make an identification of these occupied resources; so the socket() interface returns an identifier that identifies the occupied resource, and this identifier is an integer value. So, before network communication, we need to call the socket() interface to make preparations. What preparations should we do? It is to apply to the operating system for the resources needed for communication; so after the communication is completed, the requested resources must be released. Generally, I use the close (resource identifier) ​​interface to release the resources requested by the previous communication.
  • 3. What else can socket() do? socket() can also be used to communicate between local processes!

Server-side code combat:

1. Simple server-side code combat:

Let's look at a simple server-side code first:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main()
{
    
    
	int server = 0;
	int client = 0;
	struct sockaddr_in saddr = {
    
    0};
	struct sockaddr_in caddr = {
    
    0};
	socklen_t asize = 0;
    
    server = socket(PF_INET,SOCK_STREAM,0);
    if(server == -1)
    {
    
    
       printf("server socket error\n");
       return -1;
    }
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    saddr.sin_port = htons(8899);
    if( bind(server,(struct sockaddr*)&saddr,sizeof(saddr) == -1)
    {
    
    
       printf("server bind error\n");
       return -1;
    }
    if( listen(server , 1) == -1)//第二个参数1,表示当前接收一个客户来连接服务端
    {
    
    
       printf("server listen error\n");
       return -1;
    }
   printf("server start success\n");
 
   asize = sizeof(caddr);
   client = accept(server , (struct sockaddr*)&caddr, &asize);
   if(client == -1)
   {
    
    
     printf("client accept error\n");
     return -1;
   }
   printf("client : %d\n",client);

   close(client)
   close(server);

   return 0;
}

Before running this simple server program, let's explain a few knowledge points in the above code:

  • htonl(); He converts the native byte order to the network byte order, that is, to big endian.
  • INADDR_ANY: Monitor the connection from any network card on this machine; at the same time, it indicates "0.0.0.0", so what is the meaning of this value? The meaning is that all the connections of this machine are received. What does this sentence mean? Is it possible that some connections of this machine can be received, but some connections cannot be received? The answer is yes, this special ip address means that as long as the client connected to the host, all will be received, let's look at the following graphic explanation:
    insert image description here
  • After the accept() interface is called, it will be in a blocked state. The blocked state means a state of waiting. The accept function will not return until there is a client connection. If there is no client connection, the interface will be blocked all the time. Where it is called, the code will not continue to execute downwards, that is, the entire program enters a blocked state.

Let's take a look at the operation of this program:
insert image description here
we can see that the server program does not have a client to send a connection to it now, so now this program is blocked here, and this state will not be changed until a client comes to connect!

So now let's use the network debugging assistant to send a request to the server:

insert image description here
The above is just a very simple server-side program. In actual development, the amount of code is very complicated, so we then add some content to this server-side program, so that this server-side program can do more things, such as Further send and receive data:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main()
{
    
    
	int server = 0;
	int client = 0;
	struct sockaddr_in saddr = {
    
    0};
	struct sockaddr_in caddr = {
    
    0};
    socklen_t asize = 0;
    int len = 0;
    int r = 0;
    char buffer[32] = {
    
    0};
   
    server = socket(PF_INET,SOCK_STREAM,0);
    if(server == -1)
    {
    
    
       printf("server socket error\n");
       return -1;
    }
   saddr.sin_family = AF_INET;
   saddr.sin_addr.s_addr = htonl(INADDR_ANY);
   saddr.sin_port = htons(8899);
   //进行绑定
   if( bind(server,(struct sockaddr *)&saddr,sizeof(saddr) == -1)
   {
    
    
      printf("server bind error\n");
      return -1;
   }
  //进行监听有多少个客户来连接服务端,这里目前设置了一个客户端来连接服务端
   if(listen(server,1) == -1)
   {
    
    
      printf("server listen error\n");
      return -1;
   }
   //等待客户端的连接,否则一直阻塞在这个accept接口这里,直到真正有客户端连接了,才会改变这个状态
   asize = sizeof(caddr);
   client = accept(server,(struct sockaddr*)&caddr, &asize);
   
   if(client == -1)
   {
    
    
      printf("client accept error\n");
      return -1;
   }
   len = 0;
   do
   {
    
    
      int i = 0;
      r = recv(client,buffer,sizeof(buffer),0);
      //这里判断接收到的字符长度是否大于0
      if(r > 0)
      {
    
    
        len +=r;
      }
      for(i=0;i<r;i++)
      {
    
    
         printf("%c",buffer[i]);
      } 
   }while(len < 64);//这里接收最大的字符长度为64
   
   //现在接收到了客户端发送过来的请求,那么我服务端,就要给客户端发送一些数据了,有求必答
   send(client ,"Hello world",12,0);
   sleep(1);//这里延时一秒的意义子在于send接口能够把数据给发送出去
    
   //释放掉申请的资源
   close(server);
   close(client); 
   return 0;
}

Let's look at the experimental phenomenon:

insert image description here
Now it is blocked here because my client has not sent a request to the server, so I will send the request now, and I use the network debugging assistant to send it here:

GET /index.html HTTP/1.1
HOST: www.baidu.com
User-Agent: TEST
Connection: close

insert image description here

The final effect is as follows:

insert image description here
We can see that the network debugging assistant has received the Hello World sent by the server! Very perfect, perfect.

Summarize:

1. The core mode of client/server programming:

  • The server runs for a long time (infinite loop) to receive client requests
  • After the client connects, send a request (protocol data) to the server!

Guess you like

Origin blog.csdn.net/Dada_ping/article/details/127760750