Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions Server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# tcpip
TCP/IP client/server (support many clients)

______________________________________________________
Сервер
______________________________________________________

Стандартні дії та їх логіку по створенню клієнта я описала
в рефераті і позначила їх межі коментарями у коді. Тут я опишу
деякі додаткові рішення специфічні для конкретно цього
завдання і можливо трохи більш продвинуті.

Оскільки кожен клієнт має мати свій ідентифікатор зареєстрований
на сервері, то я створюю масив clients_id де і-тому місці
стоїть ідентифікатор того клієнта, якого обслуговує і-тий
файловий дескриптор. По ходу програми саме за допомогою
цього масива реалізовується зв'зка ідентифікатора клаєнта
та номером файлового дескриптора через який помжна надсилати/
приймати повідомлення і таким чином я уникаю двомірних масивів
для цієї задачі.

Всі наступні дії детально описані в коментарях у коді.

________________________________________________________
Клієнт
________________________________________________________

Стандартні дії та їх логіку по створенню клієнта я описав
в рефераті і позначив їх межі коментарями у коді. Тут я опишу
деякі додаткові рішення специфічні для конкретно цього
завдання і можливо трохи більш продвинуті.

Функції writeToServer та readFromServer досить тривіальні:
одна постійно чекає ввід в консоль від користувача, а інша
постійно перевіряє чи сервер нічого не відправив та якщо
відправив -- виводить на екран.

Для початку варто зрозуміти, що наш клієнт має приймати
повідомлення від сервера постійно, а не лише, так би мовити,
"парами" (сам надіслав дані, а тоді чекає відповіді від сервера).
Я реалізувала незалежність процесів прийняття і відправки
даних у клієнті за допомогою виділення двох додаткових потоків:
один з яких забезпечує перманентну роботу функції writeToServer(),
а інший роботу readFromServer().

Створення нових процесів відбувається досить просто за допомогою
ф-ції pthread_create() (хедерфайл pthread.h).

Для того, щоб гарненько вийти з програми і просто потренуватись
перехоплювати сигнали я створила змінну flag (додав до неї кваліфікатор
volatile -- він зберігає змінну від оптимізації процесором, адже
процесор може перемістити її в кеш, що додасть деякі складнощі
у доступі до неї з різних процесів, а процесів у нас вже більше одного).
Отже під час натискання ctrl+c флаг змінює своє значення на 1 --
нескінченний цикл завершується.
Binary file added Server/bin/cli_test_c
Binary file not shown.
Binary file added Server/bin/cli_test_cpp
Binary file not shown.
Binary file added Server/bin/server_test_cpp
Binary file not shown.
Binary file added Server/bin/srv_test_c
Binary file not shown.
Binary file added Server/client_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Server/client_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Server/server.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
140 changes: 140 additions & 0 deletions Server/src/Server_C/cli.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/** @file cli.c
* @brief implementation of methods for client part.
*
*
*
*
* @author Kekalo Kateryna
*/




#include "cli.h"

int sock;
char * cli_id;
char client_name[20];

volatile sig_atomic_t flag = 0;

void catch_ctrl_c_and_exit(int sig){
flag = 1;
}


void * writeToServer(void *arg ){

InputOutput * args = arg;

int nbytes;
char buf[BUFLEN];

while(1){
fprintf(args->outstream, "Enter message starting with 'user_name | '");
fscanf(args->instream, "%s", buf );
buf[strlen(buf)-1] = 0;

nbytes = write(sock, buf, strlen(buf)+1);
if (nbytes < 0) break;
if (strstr(buf, "stop")) break;
}
catch_ctrl_c_and_exit(2);

}


void * readFromServer (void *arg) {

InputOutput * args = arg;
int nbytes;
char buf[BUFLEN];

while(1){
nbytes = read(sock, buf, BUFLEN);
if ( nbytes < 0 ) {
perror("Read error\n");
break;
}else if (nbytes == 0) {
fprintf(args->outstream, "\nServer no message\n");
break;
}
else {
fprintf(args->outstream, "\n[server] %s\n", buf);
}
}
}

void cli(FILE * instream, FILE * outstream){
signal(SIGINT, catch_ctrl_c_and_exit);

fprintf(stdout, "Enter your nickname: ");
fscanf(instream, "%s", client_name);


int err;
struct sockaddr_in server_addr;
struct hostent *hostinfo;
hostinfo = gethostbyname(SERVER_NAME);
if ( NULL == hostinfo ) {
fprintf (stderr, "Unknown host %s. \n", SERVER_NAME);
exit (EXIT_FAILURE);
}


// Створення сокета
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr = *(struct in_addr*) hostinfo->h_addr;

sock = socket(AF_INET, SOCK_STREAM, 0);
if ( sock < 0 ) {
perror ("Client: socket was not created ");
exit (EXIT_FAILURE);
}


// Під'єднання до сервера
err = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
if ( err < 0 ) {
perror("Client: connect failure");
exit(EXIT_FAILURE);
}
fprintf(outstream, "Connection is ready\n");

// Передача ідентифікатора клієнта
write(sock, client_name, strlen(client_name)+1);

//заповнення структури для різних можливостей вводу виводу
InputOutput *args = malloc(sizeof *args);
args->instream = instream;
args->outstream = outstream;

//створення нових потоків
pthread_t write_to_server;

if (pthread_create(&write_to_server, NULL, &writeToServer, args) != 0) {
perror("Create pthread error!\n");
exit(EXIT_FAILURE);
}

pthread_t read_from_server;

if (pthread_create(&read_from_server, NULL, &readFromServer, args) != 0) {
perror("Create pthread error!\n");
exit(EXIT_FAILURE);
}

while(1){
if (flag) break;
}
fprintf(outstream, "The end\n");

close(sock);
exit (EXIT_SUCCESS);

}




71 changes: 71 additions & 0 deletions Server/src/Server_C/cli.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/** @file cli.h
* @brief declaration of methods and headers for client part.
*
*
*
*
* @author Kekalo Kateryna
*/




#ifndef CLI_H
#define CLI_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <ctype.h>
#include <locale.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>



#define SERVER_PORT 5555
#define SERVER_NAME "127.0.0.1"
#define BUFLEN 512

///type for arguments to pass in thread creating function
typedef struct {
FILE * instream;
FILE * outstream;
}InputOutput;


void cli(FILE * instream, FILE * outstream);
/** @brief main initializing function of tcp client
*
* @param stream for input username and messages
* @param stream for output messages about runtime actions
*/


void * writeToServer (void *arg);
/** @brief This function get user input and send messages to server.
*
* running in separate thread
* @param pointer to InputOutput structure
*/




void * readFromServer (void *arg);
/** @brief This function read messages from server and output them.
*
* running in separate thread
* @param pointer to InputOutput structure
*/


void catch_ctrl_c_and_exit(int sig);
/** @brief handler for signal
*/

#endif
7 changes: 7 additions & 0 deletions Server/src/Server_C/cli_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "cli.h"


int main(){
cli(stdin, stdout);
return 0;
}
Loading