select usage of local socket s

Keywords: socket network

Learn the use of socket select ion, the following code is mostly from the Internet, but the definition of socket in the network part is changed to the definition of local socket, if there is any offence, please contact me, I immediately delete, thank you.

client side

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

#include <sys/time.h>

#define MAXLINE 5
#define SERV_PORT 6000

//Notice that the input is stdin and the acceptance is sent by server.
//So the client side also needs to select for processing.
void send_and_recv( int connfd )
{
    FILE * fp =stdin;
   int   lens;
    char send[MAXLINE];
    char recv[MAXLINE];
    fd_set rset;
    FD_ZERO(&rset );
    int maxfd =( fileno( fp ) > connfd ? fileno( fp ) :connfd  + 1);   
                                    //Maximum input and output
    int n;
    int byte_size;
    int i;   
  
    int nRet;
    struct timeval tmout;
    tmout.tv_sec = 0;
    tmout.tv_usec = 0;


    while( 1)
    {

       FD_ZERO(&rset);

       FD_SET(fileno( fp ), &rset );
       FD_SET(connfd, &rset);         //Be careful not to think of rset as a simple variable
                                    //Notice that it can actually contain a set of sockets.
                                    //It's equivalent to an encapsulated array! Every time it's new!
 
   
       if( select(maxfd, &rset, NULL, NULL, &tmout ) == -1 )
       {
         printf("Client Select Error..\n");
         exit(EXIT_FAILURE  );
       }
      
      //If Connection Port has information
       if(FD_ISSET( connfd, &rset ))   //If connection port has information
       {
          printf("client get from server ...\n" );
          memset(recv, 0, sizeof( recv ) );
          n = read(connfd, recv, MAXLINE );
          if( n == 0)
          {
             printf("Recvok...\n");            break;
          }
          else if( n== -1 )
          {
             printf("Recverror...\n");
             break;
          }
          else
          {
             lens =strlen( recv );
             recv[lens] ='\0';
            //Write about stdout
             write(STDOUT_FILENO, recv, MAXLINE );
            printf("\n");
            byte_size = ( strlen(recv) ) * sizeof(char);
            printf("Client recv bytes : %d\n",byte_size);
          }

       }
      
      //If has stdin input
       if(FD_ISSET( fileno( fp ), &rset ))   //If has input
       {
         //!> printf("client stdin ...\n");
         
          memset(send, 0, sizeof( send ) );
          if( fgets(send, MAXLINE, fp ) == NULL )
          {
            printf("End...\n");
             exit(EXIT_FAILURE );
          }
          else
          {
            //!>if( str )
             lens =strlen( send );
             send[lens-1]= '\0';      //The reason for subtracting one is not to return the car characters.
                                 //Experience: This step is very important!!!!!!!!
             if( strcmp(send, "q" ) == 0 )
             {
                printf("Bye..\n" );
               return;
             }
          for(i=0; i<5; i++) //Test, five times in a row, to see how the server returns
	   {
             printf("Client send : %s\n", send);
             byte_size = ( strlen(send) ) * sizeof(char);
	     printf("Client send bytes : %d\n",byte_size);
             write(connfd, send, strlen( send ));
 
	   } 
             memset(send, 0, sizeof( send ) );

	 }
       }
      
    }
   
}

int main( int argc, char ** argv )
{
   //!> char * SERV_IP = "10.30.97.188";
    char   buf[MAXLINE];
   int     connfd;
    struct sockaddr_un servaddr;
   
   // if( argc !=2 )
    {
     // printf("Input server ip !\n");
      // exit(EXIT_FAILURE );
    }
   
   //Create sockets
    if( ( connfd= socket( AF_UNIX, SOCK_STREAM, 0 ) ) == -1 )
    {
      printf("Socket Error...\n" , errno );
       exit(EXIT_FAILURE );
    }

   //Socket Information
  // bzero(&servaddr, sizeof(servaddr));
   servaddr.sun_family = AF_UNIX;
   strcpy(servaddr.sun_path,"selectfile");
  // servaddr.sin_port = htons(SERV_PORT);
  // inet_pton(AF_INET, argv[1],&servaddr.sin_addr);
   
   //!> Link server
    if( connect(connfd, ( struct sockaddr * )&servaddr, sizeof( servaddr ) ) < 0)
    {
      printf("Connect error..\n");
      exit(EXIT_FAILURE);
   }   
   

   //!>
   //!> send and recv
   send_and_recv( connfd );
   
   //!>

    close(connfd );
   printf("Exit\n");
   
    return 0;
}
This code has one thing to note: send [lens-1]='\ 0'; This sentence made me feel a bit hard when testing. The size of the data I defined is 5 bytes, but every time I send 3 bytes of data, the server can return normally, but when I send 4 or 5 bytes, the server only returns the first three bytes. For example, when I input 123, the client will send five consecutive bytes. The server also returns 123 five times, but if I type 12345, the client sends 123 five times, the server returns 123 five times, and the server returns 123 five times, but I press the return immediately, then the client sends 5 times in a row, then 0 five times, and the server returns 5 times, but not five times. I think this is the cause of buffer accumulation (if you know the error, please criticize, thank you).

server side

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h> 

#include <sys/time.h>

#define BUF_LEN 3
#define SERV_PORT 6000
#define FD_SIZE 100
#define MAX_BACK 100
#define SOC_FD "selectfile"

int main( int argc, char ** argv )
{
 
   unlink(SOC_FD);
   int          listenfd,connfd, sockfd, maxfd, maxi, i;
    int          nready,client[FD_SIZE];      //Receive the return value of select and save the client socket
    int          lens;
    ssize_t   n;            //!> read bytes
   fd_set       rset,allset;   //Don't understand that achievements can only be saved one. In fact, fd_set is a bit like an encapsulated array.
    char      buf[BUF_LEN];            
   socklen_t   clilen;
    struct sockaddr_un servaddr, chiaddr;
 
    int j,nRet;

    struct timeval tmout;
    tmout.tv_sec = 0;
    tmout.tv_usec = 0;

  
    if( (listenfd = socket( AF_UNIX, SOCK_STREAM, 0 ) ) == -1 )
    {
       printf("Create socket Error : %d\n", errno );
       exit(EXIT_FAILURE );
    }
   
   //!>
   //The following is the interface information
   // bzero(&servaddr, sizeof( servaddr ) );
   servaddr.sun_family = AF_UNIX;
   strcpy(servaddr.sun_path, SOC_FD);  
   //servaddr.sin_addr.s_addr  =htonl( INADDR_ANY);
  // servaddr.sin_port = htons( SERV_PORT );
   
   //!>
   //!> Binding
    if( bind(listenfd, ( struct sockaddr * )&servaddr, sizeof(servaddr ) ) == -1 )
   {   
       printf("BindError : %d\n", errno);
      exit(EXIT_FAILURE  );
    }
   
   //!>
   //MONITORING
    if( listen(listenfd, MAX_BACK ) == -1 )
    {
      printf("Listen Error : %d\n", errno );
       exit(EXIT_FAILURE );
    }
   
   //The most interesting socket fd at present
    maxfd =listenfd;   //!> Maximum fd currently notifiable
    maxi =-1;         //!> Just for the benefit of client arrays
   
    for( i = 0;i < FD_SIZE; i++)   //!> First put it all-1.
    {
       client[i] =-1;      //First of all, there is no client waiting queue, so all of them are set to -1.
    }
   
    FD_ZERO(&allset);      //Set it to 0 first.
    FD_SET(listenfd, &allset );
               //Explain that I am currently interested in this socket, and let me know next time you select!   

     while( 1)
    {
       rset =allset;//Because allset may change after each cycle, it is assigned once at a time.
       if( (nready= select( maxfd + 1, &rset, NULL, NULL, &tmout )) ==-1)
      {               //If there is concern
         printf("Select Erorr : %d\n", errno );
          exit(EXIT_FAILURE );
       }
      
       if( nready<= 0)         //If all the interests are not there, go back to select
       {
         continue;
       }
      
      
   
       if(FD_ISSET( listenfd, &rset ))         //If is the "call" on the listening interface.
      {                                 //!>
         //!> printf("server listen ...\n");
          clilen =sizeof( chiaddr );
         
         printf("Start doing... \n");
         
            if( (connfd  = accept( listenfd, (struct sockaddr*)&chiaddr, &clilen ) ) == -1)
           {                              //Acept returns sockets
               printf("Accept Error : %d\n", errno );
              continue;
            }
           
           
            for( i = 0;i < FD_SIZE; i++)   //Notice that there must be a loop here, at first I thought.
                                      //!> Set an end_i to go directly.
                                      //Reason, the essence is not possible! Because each socket
           {                           //The exit time of the word is different.
               if(client[i] < 0)            //Maybe quit first, then it's messy, so only
              {                        //That's it!
                  client[i] =connfd;         //Save client's request connection
                  break;
               }
            }
           
            if( i ==FD_SIZE )            //!> The last one
            {
               printf( "Tomany ... " );
               close(connfd );         //If it's full, then it won't connect to you. Close it.
            continue;               //!> Return
            }
                                 //The function of listen is to add sockets to the array!
          FD_SET(connfd, &allset);   //!> Explain that you are also interested in this connection now!
                                 //So join the allset team.
          if( connfd> maxfd)         //This is still an array model to solve the mess.
                                 //!> Processing
          {
             maxfd =connfd;
          }
         
          if( i> maxi)               //!>Ibid.
          {
             maxi =i;
          }
       }
       
       //Here's how to deal with data functions (essentially select or serial)
       for( i = 0;i <= maxi; i++)      //Processing of all connection requests
       {

          if( ( sockfd= client[i] ) > 0)   //Or for irregular arrays
         {         //In other words, the client array is not a continuous full positive number or - 1, which may be zigzag.
             if(FD_ISSET( sockfd, &rset ))   //If the current data socket has something to read
              {
                 memset( buf,0, sizeof( buf ));   //This step is important. Don't make mistakes sometimes.
 
	         sleep(1);            
                 n = read(sockfd, buf, BUF_LEN);
                 if( n< 0 )
                 {
                   printf("Error!\n");
                    close(sockfd );         //Explain that there was a mistake on this request port!
                   FD_CLR(sockfd, &allset );
                   client[i] =-1;
                  continue;
                 }
                if( n == 0)
                {
                   printf("nodata\n");
                   close(sockfd );         //Explain that you have read it on this request port!
                   FD_CLR(sockfd, &allset );
                   client[i] =-1;
                  continue;
                }
    
		  buf[n]= '\0';
             	  printf("Server Recv: %s\n", buf);
               
                	if( strcmp(buf, "q" ) == 0)            //Client enters "q" exit flag
                	{
                       	  close(sockfd );
                  	  FD_CLR(sockfd, &allset );
                  	  client[i] =-1;
                 	  continue;
              	        }
               
              	 printf("Server send : %s\n", buf);
                
	      	 write(sockfd, buf, n);      //Write in what you read!
              	 printf("\n");
	        
                 memset( buf,0, sizeof( buf ));   //This step is important. Don't make mistakes sometimes.
	
             }

          }
       }
      
    }
  
    return 0;
}

There are also changes on the server side: sleep (1); some people will say that the use of select is to get the message back immediately without blocking the thread, but here is because my little demo has a for loop on the client side (sending data five times in a row). As mentioned above, when sending is faster than receiving, buffer accumulation, and the network (local feeling is the same, you can look at the server side). As a kind of network server, I always feel that this understanding is strange. I hope some experts can tell me how to explain it correctly.) Writing a function is not responsible for returning all the data after writing it. Based on the above two points, I added sleep. If not, the client sends five messages in a row (assuming 123), and the server returns five 123, but not necessarily five, maybe two, three or five.

Posted by john_6767 on Sun, 16 Jun 2019 12:13:01 -0700