📜 ⬆️ ⬇️

Client server under linux on c ++ communication of “all with all” clients using streams

To begin with, that was offered a job for the post of programmer with \ with ++. The job is the name of the topic.


I got on the Internet, everything was crammed with chat rooms and client-server communication, but alas, I did not find the code with a similar task. There was a client-server echo-type primitive, which I decided to base:
This is our client:


struct sockaddr_in addr; //    struct hostent* hostinfo; port = atoi(PORT); sock = socket(AF_INET, SOCK_STREAM, 0); //  TCP- if(sock < 0) { perror("socket"); exit(1); } //    addr.sin_family = AF_INET; //  Internet addr.sin_port = htons(port); //    ... addr.sin_addr.s_addr = inet_addr("127.0.0.1"); if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) //     { perror(""); exit(2); } 

This is the server code:


 if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } //set master socket to allow multiple connections , this is just a good habit, it will work without this if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 ) { perror("setsockopt"); exit(EXIT_FAILURE); } //type of socket created address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons( PORT ); //bind the socket to localhost port 8888 if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0) { perror("bind failed"); exit(EXIT_FAILURE); } printf("Listener on port %d \n", PORT); //try to specify maximum of 3 pending connections for the master socket if (listen(master_socket, 3) < 0) { perror("listen"); exit(EXIT_FAILURE); } //accept the incoming connection addrlen = sizeof(address); puts("Waiting for connections ..."); while(TRUE) { if ((new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) { perror("accept"); exit(EXIT_FAILURE); } } 

After all this, the client needs to send a message to the server using the send or write functions and, on the server side, accept the message and forward it back to the client using the read and send functions.


In general, there are different functions for sending and receiving, for example, send and recv send a confirmation flag along with the message, and the read and write functions do not require confirmation, that is, the message may lose bytes when sent and it will not be fixed.


Since sockets are duplex and creating a connection between the client and the server, we cannot write messages from other connected sockets there, it is necessary to create an array with all active sockets connected to the server. And one more note is very important:


To communicate between multiple sockets, you must use the select function, which selects a socket from the list and sends a message to it, and so on, until all the recorded sockets are finished

 //clear the socket set FD_ZERO(&readfds); //add master socket to set FD_SET(master_socket, &readfds); max_sd = master_socket; //add child sockets to set for ( i = 0 ; i < max_clients ; i++) { //socket descriptor sd = client_socket[i]; //if valid socket descriptor then add to read list if(sd > 0) FD_SET( sd , &readfds); //highest file descriptor number, need it for the select function if(sd > max_sd) max_sd = sd; } //wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL); if ((activity < 0) && (errno!=EINTR)) { printf("select error"); } 

After that, the correct value of the connected socket will be written to the array of sockets, and then it remains only to sort them when sending messages:


 sd = client_socket[i]; if (FD_ISSET( sd , &readfds)) { //Check if it was for closing , and also read the incoming message if ((valread = read( sd , buffer, 1024)) == 0) { //Somebody disconnected , get his details and print getpeername(sd , (struct sockaddr*)&address , (socklen_t*)&addrlen); printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port)); //Close the socket and mark as 0 in list for reuse close( sd ); user_count--; client_socket[i] = 0; } //Echo back the message that came in else { //set the string terminating NULL byte on the end of the data read buffer[valread] = '\0'; for (i = 0; i < max_clients; i++) { sd = client_socket[i]; send(sd , buffer , strlen(buffer) , 0 ); } buffer[1024] = {0}; } } 

Let's write all this into a function and create a separate thread:


 void *server(void *); pthread_create(&threadA[0], NULL, server, NULL); pthread_join(threadA[0], NULL); 

With regards to the client, it is necessary to create two different threads for reading and writing to the socket:


 void *write(void *); void *read(void *); pthread_create(&threadA[0], NULL, write, NULL); pthread_create(&threadA[1], NULL, read, NULL); pthread_join(threadA[1], NULL); pthread_join(threadA[0], NULL); void *write (void *dummyPt) { for(;;) { char s[BUF_SIZE]; cout << "<----"; bzero(s, BUF_SIZE + 1); cin.getline(s, BUF_SIZE); send(sock, s, strlen(s), 0); } close(sock); } void *read (void *dummyPt) { char test[BUF_SIZE]; bzero(test, BUF_SIZE + 1); bool loop = false; while(!loop) { bzero(test, BUF_SIZE + 1); int rc = read(sock, test, BUF_SIZE); if ( rc > 0) { string tester (test); cout << ": "<< tester << endl; if(tester == "exit_server") break; } } cout << "\nClosing thread and conn" << endl; close(sock); } 

Now everything works. Thanks for taking off. I hope that this is useful to those who, just like I tried to write a client-server, but could not find the necessary information on the network.


')

Source: https://habr.com/ru/post/357566/


All Articles