MIPI_AdvancedC_FRTK/Seminar1/HW/client_bytestuff.c

208 lines
7.6 KiB
C
Raw Permalink Normal View History

2024-11-14 08:45:50 +03:00
/*!
* Simple chat program (client 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>
#include <netdb.h>
int main()
{
/* ---------- ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ КЛИЕНТА---------- */
/*
1. client - файл-дескриптор, хранящий значение сокета,
которые вернула система при подключении к серверу.
2. portNum нужен для хранения номера порта, на котором происходит соединение.
3. isExit - булевая переменная, признак завершения программы.
4. Клиент считывает сообщение из сокета соединения в буффер обмена для приема/отправки данных к/от сервера
5. 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 будет содержать адрес сервера
*/
int client;
int portNum = 1500; // Номер порта один для сервера и клиента!
bool isExit = false;
int bufsize = 1024;
char buffer[bufsize];
char* ip = "127.0.0.1";
struct sockaddr_in server_addr;
/*
Socket() функция создает новый сокет.
На вход получает 3 аргумента,
a. AF_INET: доменный адрес сокета.
b. SOCK_STREAM: тип сокета. Потоковый сокет, в котором сообщение
читается последовательным потоком(TCP).
c. Третий это аргумент протокола: всегда должен быть 0.
Операционная система выберет самый подходящий протокол.
Функция возвращает файл-дескриптор целое число - соединение, которое используется для всех ссылок
на этот сокет. Если произошла ошибка соединения, то возвращается -1.
*/
/* ---------- УСТАНОВКА СОКЕТ ПОДКЛЮЧЕНИЯ ----------*/
/* --------------- socket() функция ------------------*/
client = socket(AF_INET, SOCK_STREAM, 0);
printf("CLIENT\n");
if (client < 0)
{
printf("Error establishing socket...\n");
exit(1);
}
printf("=> Socket client has been created...\n");
/*
Переменная serv_addr - это структура sockaddr_in.
sin_family содержит код для адресной семьи.
Всегда должна быть установлена AF_INET.
htons() переводит номер порта из порядка байтов хоста
в номер порта в порядке байтов сети.
*/
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portNum);
// эта функция возвращает 1, если IP-адрес действительный
// и 0, если недействительный
// inet_pton переводит IP-адрес в пакеты
// inet_ntoa переводит обратно из пакета в IP-адрес
inet_pton(AF_INET, ip, &server_addr.sin_addr);
/* ---------- СОЕДИНЕНИЕ СОКЕТА ---------- */
/* ---------------- connect() ---------------- */
if (connect(client,(struct sockaddr *)&server_addr, sizeof(server_addr)) == 0)
printf("=> Connection to the server %s with port number: %d\n",inet_ntoa(server_addr.sin_addr),portNum);
if (connect(client,(struct sockaddr *)&server_addr, sizeof(server_addr)) == 0)
printf("=> Connection to the server port number: %d \n",portNum);
/*
Функция connect вызывается клиентом для установки соединения с сервером.
Ей нужны 3 аргумента: файловый дескриптор сокета, адрес хоста, к которому
клиент хочет подключится (включая номер порта), и размер адреса.
Функция возвращает 0 при успехе и 1 при неудаче.
Примечание: клиенту нужно знать номер порта сервера,
а не свой номер порта.
*/
printf("=> Awaiting confirmation from the server...\n");
recv(client, buffer, bufsize, 0);
printf("=> Connection confirmed, you are good to go...\n");
printf("\n\n=> Enter # to end the connection\n");
// При достижении соединения, клиент может послать сообщение первым.
do {
char c;
printf("Client: ");
c = 0x7E;
send(client, &c, 1, 0); //SOP
do
{
c = getchar();
if(c == 0x7E)
{
c = 0x7D; send(client, &c, 1, 0);
c = 0x5E; send(client, &c, 1, 0);
continue;
}
if(c == 0x7D)
{
c = 0x7D; send(client, &c, 1, 0);
c = 0x5D; send(client, &c, 1, 0);
continue;
}
send(client, &c, 1, 0);
if(c == '#')
{
isExit = true;
break;
}
} while (c != '\n');
c = 0x7E;
send(client, &c, 1, 0); //EOP
printf("Server: ");
do
{
recv(client, &c, 1, 0);
} while (c != 0x7E); //SOP
recv(client, &c, 1, 0);
while (c != 0x7E) //EOP
{
if(c == 0x7D)
{
recv(client, &c, 1, 0);
if(c == 0x5E)
{
c = 0x7E;
}
else if(c == 0x5D)
{
c = 0x7D;
}
else
{
printf("%c", 0x7D);
continue;
}
}
printf("%c", c);
if (c == '#')
{
isExit = true;
}
recv(client, &c, 1, 0);
}
} while (!isExit);
/* ---------------- ЗАВЕРШЕНИЕ СОЕДИНЕНИЯ ------------- */
/* ----------------- close() --------------- */
/*
Как только сервер нажмет # для завершения соединения,
цикл завершится и закроет серверное сокет соединение
и клиентсткое соединение.
*/
printf("\n=> Connection terminated.\n\nGoodbye...\n");
close(client);
return 0;
}