linux Network Programming -- socket server and client TCP programming and multi process programming

1. Basic communication process between client and server in network programming

2. Server and client programming < iterative server >

2.1. Iterative server programming

2.1.1. Command line parameter parsing

  1. The server parameter only has the port number. Add a help parameter < - H > to explain the usage of this command
  2. The code is written as follows
void print_usage(char *progname)
{
	printf("%s usage: \n", progname);
	printf("-p(--port): sepcify server port.\n");
	printf("-h(--Help): print this help information.\n");

	return ;
}
{
	int                  port = 0;
	int                  ch;
    struct option        opts[] = {
		{"port", required_argument, NULL, 'p'},
		{"help", no_argument, NULL, 'h'},
		{NULL, 0, NULL, 0}
	};

	while( (ch=getopt_long(argc, argv, "p:h", opts, NULL)) != -1 ) 
	{
		switch(ch)
		{
			case 'p':
				port=atoi(optarg);//String - > integer
				break;

			case 'h':
				print_usage(argv[0]);
				return 0;
		}
	}
	if(!port) //Command not used normally
	{
		print_usage(argv[0]);
		return 0;
	}
}

2.1.2. Create server socket

{
	socket_fd = socket(AF_INET, SOCK_STREAM, 0);//IPV4   TCP
    if(socket_fd < 0)
    {
        printf("Create socket failure : %s\n", strerror(errno));
        return -1;
    }
    printf("Create socket [%d] successful!\n", socket_fd);    
    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));//Prevent program port reuse error
}

2.1.3. bind bind port and ip and enable listen

{
 	memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port);       // Host byte order - > network byte order
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // Monitor all IP hosts ----- > Network
    rv = bind(socket_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    if(rv < 0)
    {
        printf("Socket[%d] bind on port [%d] failure : %s\n",socket_fd,port,strerror(errno));
        return -2;
    }
    printf("Socket[%d] bind on port [%d] successful!\n", socket_fd, port);
    
    //listen 
    listen(socket_fd, 13);
}

2.1.4. Open accept

  1. Accept is a blocking function. When no client connects to the server, the program will block and not return until a client connects. When the client calls the connect function, the accept function of the server will be triggered to return, and the TCP connection will be established.
  2. code implementation
//accept
 clifd = accept(socket_fd, (struct sockaddr *)&cliaddr, &len);
 if(clifd < 0)
 {
     printf("Accept new client failure:%s\n", strerror(errno));
     continue;
 }
 printf("Accept new client [%s:%d] successfully!\n"
 		,inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));//IP and port of the client

2.1.5. Read and write to the client through file IO system call

  1. Read client programming, using read system call
{
	memset(buf, 0, sizeof(buf));
	rv = read(clifd, buf, sizeof(buf));
	if(rv < 0)
	{
		printf("Read from client by clifd[%d] failure: %s\n", clifd , strerror(errno));
		close(clifd);
		continue;     
	}
	else if(rv == 0)
	{
		 printf("Clifd[%d] get disconnected\n", clifd);
		 close(clifd);
		 continue;
	}
	else if(rv > 0)
	{
		printf("Read [%d] byte data from client clifd[%d] : %s\n", rv, clifd, buf);
	}
}
  1. write messages to the client. Note that you do not want to continue communication after writing. You need to close the client descriptor.
{
     rv = write(clifd, MSG_STR, strlen(MSG_STR));
     if(rv < 0)    
     {             
         printf("write to client by clifd[%d] failure: %s\n", clifd , strerror(errno));
         close(clifd);
         continue;
     }  
     printf("Close client fd[%d]\n", clifd);
     close(clifd);
}
  1. Before shutting down the server, you also need to close the socket descriptor created before listening.

2.2. Client programming

2.2.1 client command line parameter resolution (with domain name resolution function)

  1. The client parameters include server IP address and server port. Add the help command < - H >, and add the domain name command < - d >. This code only resolves the domain name and prints its IP address. Since there is no public IP, it cannot be tested. baidu.com can resolve its IP address
{
	int                  ch;
    struct option        opts[] = {
		{"ipaddr", required_argument, NULL, 'i'},
		{"port", required_argument, NULL, 'p'},
        {"domain_name", required_argument, NULL, 'd'},
		{"help", no_argument, NULL, 'h'},
		{NULL, 0, NULL, 0}
	};

	while( (ch=getopt_long(argc, argv, "i:p:d:h", opts, NULL)) != -1 ) 
	{
		switch(ch)
		{
			case 'i':
				servip=optarg;
				break;

			case 'p':
				port=atoi(optarg);
				break;
            
            case 'd':
                ser_domain_name=optarg;
                break;

			case 'h':
				print_usage(argv[0]);
				return 0;
		}
	}

	if( !servip || !port || !ser_domain_name)
	{
		print_usage(argv[0]);
		return 0;
	}
    //Print domain name and resolved IP address
    p = gethostbyname(ser_domain_name);
    printf("domain_name : %s servip : %s\n", ser_domain_name, inet_ntoa(*((struct in_addr *)p->h_addr)));
}

2.2.2. Create client socket

  1. Use IPV4 and TCP communication
{
	socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(socket_fd < 0)
    {
        printf("Create socket failure :%s\n", strerror(errno));
        return -1;
    }
    printf("Create socket [%d] successful!\n", socket_fd);
}

2.2.3. connect to the server

  1. Pass in the parameters through the specification, and pay attention to byte order and string conversion
{
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port   = htons(port);// Main ---- > Network
    inet_aton(servip, &servaddr.sin_addr);    //String ----- > network byte order
    
    rv = connect(socket_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    if(rv < 0)
    {
        printf("Connect to server [%s:%d] failure : %s\n", servip, port, strerror(errno));
        return -2;
    }
    printf("Connect to server [%s:%d] successful!\n", servip, port);
}

2.2.4. Read and write to the server through file IO system call

  1. Like the server, read and write are used to read and write messages
  2. Note that after the communication between the client and the server ends, the socket descriptor can be closed if you do not want to continue the communication
{
	rv = write(socket_fd, MSG_STR, strlen(MSG_STR));
	if(rv < 0)
	{
	    printf("Write to server by socket_fd [%d] failure : %s\n", socket_fd, strerror(errno));
	    break;
	}
	
	//read
	memset(buf, 0, sizeof(buf));
	rv = read(socket_fd, buf, sizeof(buf));
	if(rv < 0)
	{
	    printf("Read from server by sockfd[%d] failure: %s\n", socket_fd , strerror(errno));
	    break;    
	}
	else if(0 == rv)
	{
	    printf("Socketfd[%d] get disconnected\n", socket_fd);
	    break;
	}
	else if(rv > 0)
	{
	    printf("Read [%d] byte from server socket_fd [%d] : %s\n", rv, socket_fd, buf);
	}
	close(socket_fd);
}

3. Server + multi process programming

3.1. Brief introduction to multi process programming

  1. The iterative server can only communicate with one client at a time. In fact, a large number of clients will access and communicate with the server. At this time, the iterative server is no longer applicable.
  2. The concurrent server is realized by multi process programming, and the structural block diagram is as follows

3.2 programming

  1. Multi process programming, modify the original server code, and open the sub process to communicate with the client after receiving the client connection request
{
	pid = fork();
	if(pid < 0)
	{
	    printf("fork() create child process failure : %s\n", strerror(errno));
	    close(cli_fd);
	}
	else if(pid > 0) // Function of parent process
	{
	    close(cli_fd); //The parent process does not require a client descriptor
	    continue;
	}
	else if(0 == pid)
	{
		close(socket_fd); //The child process does not need the fd. The fd is used for listening. After listening, a new fd is used
		....//Communication between server and client
	}
}

Keywords: Linux network server

Added by eduard on Fri, 12 Nov 2021 17:57:09 +0200