Сокеты клиент сервер линукс

How to Code a Server and Client in C with Sockets on Linux – Code Examples

In a previous example we learnt about the basics of socket programming in C. In this example we shall build a basic ECHO client and server. The server/client shown here use TCP sockets or SOCK_STREAM.

Tcp sockets are connection oriented, means that they have a concept of independent connection on a certain port which one application can use at a time.

The concept of connection makes TCP a «reliable» stream such that if errors occur, they can be detected and compensated for by resending the failed packets.

Server

Lets build a very simple web server. The steps to make a webserver are as follows :

1. Create socket
2. Bind to address and port
3. Put in listening mode
4. Accept connections and process there after.

/* C socket server example */ #include #include //strlen #include #include //inet_addr #include //write int main(int argc , char *argv[]) < int socket_desc , client_sock , c , read_size; struct sockaddr_in server , client; char client_message[2000]; //Create socket socket_desc = socket(AF_INET , SOCK_STREAM , 0); if (socket_desc == -1) < printf("Could not create socket"); >puts("Socket created"); //Prepare the sockaddr_in structure server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons( 8888 ); //Bind if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0) < //print the error message perror("bind failed. Error"); return 1; >puts("bind done"); //Listen listen(socket_desc , 3); //Accept and incoming connection puts("Waiting for incoming connections. "); c = sizeof(struct sockaddr_in); //accept connection from an incoming client client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c); if (client_sock < 0) < perror("accept failed"); return 1; >puts("Connection accepted"); //Receive a message from client while( (read_size = recv(client_sock , client_message , 2000 , 0)) > 0 ) < //Send the message back to client write(client_sock , client_message , strlen(client_message)); >if(read_size == 0) < puts("Client disconnected"); fflush(stdout); >else if(read_size == -1) < perror("recv failed"); >return 0; >

The above code example will start a server on localhost (127.0.0.1) port 8888
Once it receives a connection, it will read some input from the client and reply back with the same message.
To test the server run the server and then connect from another terminal using the telnet command like this

Client

Now instead of using the telnet program as a client, why not write our own client program. Quite simple again

/* C ECHO client example using sockets */ #include //printf #include //strlen #include //socket #include //inet_addr #include int main(int argc , char *argv[]) < int sock; struct sockaddr_in server; char message[1000] , server_reply[2000]; //Create socket sock = socket(AF_INET , SOCK_STREAM , 0); if (sock == -1) < printf("Could not create socket"); >puts("Socket created"); server.sin_addr.s_addr = inet_addr("127.0.0.1"); server.sin_family = AF_INET; server.sin_port = htons( 8888 ); //Connect to remote server if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) < perror("connect failed. Error"); return 1; >puts("Connected\n"); //keep communicating with server while(1) < printf("Enter message : "); scanf("%s" , message); //Send some data if( send(sock , message , strlen(message) , 0) < 0) < puts("Send failed"); return 1; >//Receive a reply from the server if( recv(sock , server_reply , 2000 , 0) < 0) < puts("recv failed"); break; >puts("Server reply :"); puts(server_reply); > close(sock); return 0; >

The above program will connect to localhost port 8888 and then ask for commands to send. Here is an example, how the output would look

$ gcc client.c && ./a.out Socket created Connected Enter message : hi Server reply : hi Enter message : how are you

Server to handle multiple connections

The server in the above example has a drawback. It can handle communication with only 1 client. Thats not very useful.

Читайте также:  Открыть графический интерфейс linux

One way to work around this is by using threads. A thread can be assigned for each connected client which will handle communication with the client.

/* C socket server example, handles multiple clients using threads */ #include #include //strlen #include //strlen #include #include //inet_addr #include //write #include //for threading , link with lpthread //the thread function void *connection_handler(void *); int main(int argc , char *argv[]) < int socket_desc , client_sock , c , *new_sock; struct sockaddr_in server , client; //Create socket socket_desc = socket(AF_INET , SOCK_STREAM , 0); if (socket_desc == -1) < printf("Could not create socket"); >puts("Socket created"); //Prepare the sockaddr_in structure server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons( 8888 ); //Bind if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0) < //print the error message perror("bind failed. Error"); return 1; >puts("bind done"); //Listen listen(socket_desc , 3); //Accept and incoming connection puts("Waiting for incoming connections. "); c = sizeof(struct sockaddr_in); //Accept and incoming connection puts("Waiting for incoming connections. "); c = sizeof(struct sockaddr_in); while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) ) < puts("Connection accepted"); pthread_t sniffer_thread; new_sock = malloc(1); *new_sock = client_sock; if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0) < perror("could not create thread"); return 1; >//Now join the thread , so that we dont terminate before the thread //pthread_join( sniffer_thread , NULL); puts("Handler assigned"); > if (client_sock < 0) < perror("accept failed"); return 1; >return 0; > /* * This will handle connection for each client * */ void *connection_handler(void *socket_desc) < //Get the socket descriptor int sock = *(int*)socket_desc; int read_size; char *message , client_message[2000]; //Send some messages to the client message = "Greetings! I am your connection handler\n"; write(sock , message , strlen(message)); message = "Now type something and i shall repeat what you type \n"; write(sock , message , strlen(message)); //Receive a message from client while( (read_size = recv(sock , client_message , 2000 , 0)) >0 ) < //Send the message back to client write(sock , client_message , strlen(client_message)); >if(read_size == 0) < puts("Client disconnected"); fflush(stdout); >else if(read_size == -1) < perror("recv failed"); >//Free the socket pointer free(socket_desc); return 0; >

Run the above server and connect from multiple clients and it will handle all of them. There are other ways to handle multiple clients, like select, poll etc.

Читайте также:  Filesystems supported by linux

We shall talk about them in some other article. Till then practise the above code examples and enjoy.

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected] .

64 Comments

  1. Zamer Chaudhary April 16, 2022 at 2:02 pm Hey sir i need you help related to Develop a client/server application using Linux TCP sockets and the C programming language.
    I will share the more information on mail. Please respond me.
    [email protected]
  1. Alex June 8, 2017 at 4:04 pm Yes, it fixes the bug with memory leakage but disables the multiple clients functionality, so this example doesn’t really work 🙁 I cann’t solve this problem yet.
  1. David November 5, 2021 at 1:01 am I’m wondering that, too. As soon as I change from the localhost address, I start getting message refused on the client.

Источник

Клиент-сервер под linux на c++ общение клиентов «все со всеми» с использованием потоков

Начну с того, что была предложена работа на должность программиста с\с++. Задание это название темы.

Полез в интернет, кругом все напичкано чатами и общением по типу клиент-сервер, но увы кода с подобным заданием я так и не нашел. Был примитив типа ЭХО клиент-сервера, который я и решил взять за основу:
Это у нас клиент:

 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) // установка соединения с сервером
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); >>

После всего этого в клиенте нужно отправить сообщение серверу используя функции send или write а на стороне сервера принять сообщение и переотправить его обратно клиенту используя функции read и send.

Читайте также:  Epson perfection v10 linux drivers

Вообще есть разные функции отправки и приема, к примеру send и recv вместе с сообщением шлют еще и флаг подтверждения, а функции read и write не требуют подтверждения, то есть сообщение может потерять байты при отправке и это не будет зафиксировано.

Так как сокеты это дуплекс и создавая связь между клиентом и сервером мы не можем писать туда сообщения из других подключенных сокетов, необходимо создать массив со всеми активными сокетами подключенными к серверу. И еще одно замечание очень важное:

Для общения между несколькими сокетами необходимо использовать функцию select, которая выбирает сокет из списка и отсылает ему сообщение, и так далее, пока не закончатся все записанные сокеты

//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

После этого в массив сокетов будет записано правильное значение подключаемого сокета а далее остается лишь перебирать их при рассылке сообщений:

 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] = ; > >

Запишем все это в функцию и создадим отдельный поток:

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

Что касаемо клиента, то необходимо создать два разных потока для чтения и записи в сокет:

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 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 > cout

Теперь все работает. Спасибо за снимание. Надеюсь что это пригодится тем, кто так же как и я пытался написать клиент-сервер, но не смог найти нужную информацию в сети.

Источник

Оцените статью
Adblock
detector