client side
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).#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; }
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.