Server program in linux

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 mint

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.

Читайте также:  Восстановление системы astra 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, с автоматическим поднятием хостов и переключением версий PHP

Скорее всего какие-то части этой статьи уже знакомы многим хаброжителям, но в связи с покупкой нового рабочего ноутбука я решил собрать все крупинки воедино и организовать удобное средство для разработки. Мне часто приходится работать со множеством маленьких проектов, с разными версиями PHP, часто переводить старые проекты на новые версии. В далёком прошлом, когда я был пользователем Windows то использовал OpenServer. Но с переходом на Linux мне нехватало той простоты создания хостов и переключений версий которые были в нём. Поэтому пришлось сделать еще более удобное решение на Linux =)

Цели

  1. Использовать текущий на момент написания статьи софт
  2. Чтоб разграничить локальные домены, будем использовать специальный домен .loc
  3. Переключения версий PHP реализуем через поддомен c помощью fast-cgi
  4. Автоматическое создание хоста с помощью vhost_alias и dnsmasq

будет запущен тот же файл но уже с версией PHP 7.2.7

Другие версии доставляются аналогичным описанным ниже способом.

Для создания еще одного сайта просто создаем в /var/www/ папку имеющую окончание .loc, внутри которой должна быть папка public_html являющаяся корнем сайта

Вот собственно и все. Как без дополнительных мучений, перезапусков, и редактирований конфигов имеем автоматическую систему для работы с сайтами.

Всё это я проверну на LinuxMint19, он на базе Ubuntu18.04, так что с ним все будет аналогично.

Для начала поставим необходимые пакеты

sudo apt update sudo apt install build-essential pkg-config libxml2-dev libfcgi-dev apache2 libapache2-mod-fcgid postfix 

Postfix ставим в качестве плюшки, как простое решение(в мастере установки, всё по умолчанию выбираем) для отправки почты с локальной машины.

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

Читайте также:  Tar linux скрытые файлы

Скопируем папку созданную апачем в домашний каталог, создадим на ее месте ссылку, не забыв поменять пользователя на себя и обменяться группами с апачем.

sudo mv /var/www/ ~/www sudo ln -s ~/www /var/www sudo chown $USER:$USER -R ~/www sudo usermod -a -G www-data $USER sudo usermod -a -G $USER www-data 

Создадим папку в которой будем собирать исходники PHP для разных версий

sudo mkdir /usr/local/src/php-build 

Также нам понадобится папки для CGI скриптов

И runtime папка для этих же скриптов, с правами

sudo mkdir /var/run/mod_fcgid sudo chmod 777 /var/run/mod_fcgid 

И так как каталог у нас находится в оперативной памяти, добавим его создание при старте системы, для этого добавим в /etc/tmpfiles.d/fcgid.conf

 #Type Path Mode UID GID Age Argument d /var/run/mod_fcgid 0755 www-data www-data - - 

У меня dnsmasq-base идет с коробки, если нет то его всегда можно доставить.

sudo updatedb locate dnsmasq.conf 

Либо если он как и у меня является частью NetworkManager то создать новый файл конфигурации в /etc/NetworkManager/dnsmasq.d/local.conf
Добавим в него строчку для перенаправление нашего локального домена на локальную машину.

Также нужно включить необходимые модули апача

sudo a2enmod fcgid vhost_alias actions rewrite 

Предварительная подготовка завершена, приступаем к сборке различных локальных версий PHP. Для каждой версии PHP проделываем следующие 4 шага. На примере 5.6.36

1. Скачиваем исходники нужной версии и распаковываем их

cd /usr/local/src/php-build sudo wget http://pl1.php.net/get/php-5.6.36.tar.bz2/from/this/mirror -O php-5.6.36.tar.bz2 sudo tar jxf php-5.6.36.tar.bz2 

2. Cобираем из исходников нужную версию PHP, и помещаем ее в /opt/php-5.6.36

sudo mkdir /opt/php-5.6.36 cd php-5.6.36 sudo ./configure --prefix=/opt/php-5.6.36 --with-config-file-path=/opt/php-5.6.36 --enable-cgi sudo make sudo make install sudo make clean 

3. Создаем CGI для обработки этой версии в /var/www/cgi-bin/php-5.6.36.fcgi

#!/bin/bash PHPRC=/opt/php-5.6.36/php.ini PHP_CGI=/opt/php-5.6.36/bin/php-cgi PHP_FCGI_CHILDREN=8 PHP_FCGI_MAX_REQUESTS=3000 export PHPRC export PHP_FCGI_CHILDREN export PHP_FCGI_MAX_REQUESTS exec /opt/php-5.6.36/bin/php-cgi 

4. Делаем файл исполняемым

sudo chmod +x /var/www/cgi-bin/php-5.6.36.fcgi 

5. Добавляем экшен для обработки каждой версии в /etc/apache2/mods-available/fcgid.conf

 AddHandler fcgid-script fcg fcgi fpl Action application/x-httpd-php-5.6.36 /cgi-bin/php-5.6.36.fcgi AddType application/x-httpd-php-5.6.36 .php #Action application/x-httpd-php-7.2.7 /cgi-bin/php-7.2.7.fcgi #AddType application/x-httpd-php-7.2.7 .php FcgidIPCDir /var/run/mod_fcgid FcgidProcessTableFile /var/run/mod_fcgid/fcgid_shm FcgidConnectTimeout 20 AddHandler fcgid-script .fcgi  

6. Добавляем правило для обработки каждой версии в /etc/apache2/sites-available/000-default.conf

 #Универсальный ServerNamе ServerAlias *.loc #Алиас для CGI скриптов ScriptAlias /cgi-bin /var/www/cgi-bin #Универсальный DocumentRoot VirtualDocumentRoot /var/www/%2+/public_html #Директория тоже должна быть универсальной Options +ExecCGI -Indexes AllowOverride All Order allow,deny Allow from all #Ниже все условия для каждой из версий =~ /56\..*?\.loc/"> SetHandler application/x-httpd-php-5.6.36 #По умолчанию, если версия не указанна, запускаем на последней SetHandler application/x-httpd-php-7.2.7   ErrorLog $/error.log CustomLog $/access.log combined 

Ну вот и всё. Осталось только перезапустить apache и dnsmasq и пользоваться

sudo service apache2 restart sudo service network-manager restart 

Источник

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