MIPI_AdvancedC_FRTK/Seminar1/52_53_server_web2.c
2024-11-14 08:45:50 +03:00

225 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* Simple chat program (server side).cpp - http://github.com/hassanyf
* Version - 2.0.1
*
* Copyright (c) 2016 Hassan M. Yousuf
*/
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
/* ---------- ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ СЕРВЕРА---------- */
/*
1. client/server - два файл-дескриптора.
Эти две перемнные хранят значение сокетов,
которые вернула система при подключении.
2. portNum нужен для хранения номера порта, на котором происходит соединение.
3. isExit - булевая переменная, признак завершения программы.
4. Сервер считывает сообщение из сокет соединения в буффер обмена для приема/отправки данных к/от сервера.
*/
int server;//файл-дескриптор сервера
int client;//файл-дескриптор клиента
int portNum = 8000;//номера порта, на котором происходит соединение (0 до 65535)
bool isExit = false;//булевая переменная, признак завершения программы.
int bufsize = 1024;//размер буффера
char buffer[bufsize]; //буффер обмена для приема/отправки данных к/от сервера
/*
5. A sockaddr_in - структура, содержащая интернет адрес, с которым будет установлено соединение.
Эта структура уже определена в netinet/in.h, поэтому нет необходимости
заново ее задавать.
DEFINITION:
struct sockaddr_in
{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
6. serv_addr будет содержать адрес сервера
7. socklen_t - длиной по крайней мере 32 бита
*/
struct sockaddr_in server_addr;
socklen_t size;
/* ---------- УСТАНОВКА СОКЕТ СОЕДИНЕНИЯ ----------*/
/* --------------- socket() функция ------------------*/
/*
Socket() функция создает новый сокет.
На вход получает 3 аргумента,
a. AF_INET: доменный адрес сокета.
b. SOCK_STREAM: тип сокета. Потоковый сокет, в котором сообщение
читается последовательным потоком(TCP).
c. Третий это аргумент протокола: всегда должен быть 0.
Операционная система выберет самый подходящий протокол.
Функция возвращает файл-дескриптор целое число - соединение, которое используется для всех ссылок
на этот сокет. Если произошла ошибка соединения, то возвращается -1.
*/
server = socket(AF_INET, SOCK_STREAM, 0);
printf("SERVER\n");
if (server < 0)
{
printf("Error establishing socket...\n");
exit(1);
}
printf("=> Socket server has been created...\n");
/*
Переменная serv_addr - структура sockaddr_in.
sin_family содержит код для адресной семьи.
Всегда должна быть установлена AF_INET.
INADDR_ANY содержит IP-адрес хоста. Для сервера - это
IP-адрес компьютера, на котором работает сервер.
htons() функция переводит номер порта из порядка байтов хоста
в номер порта в порядке байтов сети.
*/
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(portNum);
/* ---------- ПРИВЯЗКА СОКЕТА ---------- */
/* ---------------- bind() ---------------- */
/*
bind() функция привязывает сокет к адресу, то есть в нашем случае
к адресу сервера и номеру порта, на котором сервер будет работать.
Для этого нужны три аргумента: файл дескриптор сокета, указатель на структуру
типа sockaddr (должен указывать на правильный тип)
*
*/
if ((bind(server, (struct sockaddr*)&server_addr,sizeof(server_addr))) < 0)
{
printf("=> Error binding connection, the socket has already been established...\n");
return -1;
}
size = sizeof(server_addr);
printf("=> Looking for clients...\n");
/* ------------- ПРОСЛУШИВАНИЕ СОКЕТА ------------- */
/* ---------------- listen() ---------------- */
/*
Функция listen позволяет прослушивать сокета для подключения.
Программа будет в состоянии простоя, если подключений не обнаружится.
Первый аргумент - это файл дескриптор сокета, второй - количество клиентов,
то есть количество подключений, которое сервер может обработать, пока процесс
обрабатывает определенное подключение. Максимальное число клиентов во многих системах равняется 5.
*/
listen(server, 1);
/* ------------- ПОДКЛЮЧЕНИЕ КЛИЕНТОВ ------------- */
/* ----------------- accept() ------------------- */
/*
Система accept() вызывает процесс блокировки пока клиент подключается к серверу.
К тому же, она пробуждает процесс, когда подключение с клиентом было успешно установлено.
Она возвращает новый файл дескриптор, и вся связь по этому подключению должна
осуществляться, используя новый файл дескриптор. Второй аргумент - указатель на
адрес клиента, третий - размер структуры.
*/
int clientCount = 1;
while(!isExit)
{
client = accept(server,(struct sockaddr *)&server_addr,&size);
// первая проверка действительности подключения
if (client < 0)
printf("=> Error on accepting...");
//Основной цикл
if(client > 0)
{
printf("=> Connected with the client %d, you are good to go...\n",clientCount);
//.....
/*
Примечание: мы перейдем в этот момент только после того, как
клиент успешно подключится к нашему серверу.
Произойдет чтение сокета. Заметим, что read() будет
блокировать до момента наличия чего-то для чтения
Чтение будет происходить maximum 1024 символов в пакете
*/
int result = recv(client, buffer, bufsize, 0);
if (result < 0)
{
// ошибка получения данных
printf("\n\n=> Connection terminated error %d with IP %s\n",result,inet_ntoa(server_addr.sin_addr));
close(client);
exit(1);
}
// Мы знаем фактический размер полученных данных, поэтому ставим метку конца строки
// В буфере запроса.
buffer[result] = '\0';
char response[1024] = "HTTP/1.1 200 OK\r\n"
"Version: HTTP/1.1\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"\r\n\r\n"
"<!DOCTYPE HTML>"
"<html>"
" <head>"
" <meta name=\"viewport\" content=\"width=device-width,"
" initial-scale=1\">"
" </head>"
" <h1>ESP32 - Web Server</h1>"
" <p>LED #1"
" <a href=\"on1\">"
" <button>ON</button>"
" </a>&nbsp;"
" <a href=\"off1\">"
" <button>OFF</button>"
" </a>"
" </p>"
" <p>LED #2"
" <a href=\"on2\">"
" <button>ON</button>"
" </a>&nbsp;"
" <a href=\"off2\">"
" <button>OFF</button>"
" </a>"
" </p>";
strcat(response,"</html>");
printf("%s\n",buffer);
send(client, response,strlen(response), 0);
printf("\n\n=> Connection terminated with IP %s\n",inet_ntoa(server_addr.sin_addr));
close(client);
printf("\n=> Press any key and <Enter>, # to end the connection\n");
char c;
while((c=getchar())!='\n')
if(c=='#')
{
isExit=true;
}
}
}
close(server);
printf("\nGoodbye...");
isExit = false;
return 0;
}