
Лаб. 6 ОСиС
.docxЛабораторная работа 6
client.c:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <pthread.h>
struct Server {
char ip[255];
int port;
};
uint64_t MultModulo(uint64_t a, uint64_t b, uint64_t mod) {
uint64_t result = 0;
a = a % mod;
while (b > 0) {
if (b % 2 == 1)
result = (result + a) % mod;
a = (a * 2) % mod;
b /= 2;
}
return result % mod;
}
bool ConvertStringToUI64(const char *str, uint64_t *val) {
char *end = NULL;
unsigned long long i = strtoull(str, &end, 10);
if (errno == ERANGE) {
fprintf(stderr, "Out of uint64_t range: %s\n", str);
return false;
}
if (errno != 0)
return false;
*val = i;
return true;
}
struct ThreadData {
struct Server server;
uint64_t begin;
uint64_t end;
uint64_t mod;
uint64_t result;
};
void *send_request(void *arg) {
struct ThreadData *data = (struct ThreadData *)arg;
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(data->server.port);
struct hostent *hostname = gethostbyname(data->server.ip);
if (hostname == NULL) {
fprintf(stderr, "gethostbyname failed with %s\n", data->server.ip);
// pthread_exit(NULL);
exit(1);
}
server.sin_addr.s_addr = *((unsigned long *)hostname->h_addr);
int sck = socket(AF_INET, SOCK_STREAM, 0);
if (sck < 0) {
fprintf(stderr, "Socket creation failed!\n");
// pthread_exit(NULL);
exit(1);
}
if (connect(sck, (struct sockaddr *)&server, sizeof(server)) < 0) {
fprintf(stderr, "Connection failed\n");
// pthread_exit(NULL);
exit(1);
}
char task[sizeof(uint64_t) * 3];
memcpy(task, &data->begin, sizeof(uint64_t));
memcpy(task + sizeof(uint64_t), &data->end, sizeof(uint64_t));
memcpy(task + 2 * sizeof(uint64_t), &data->mod, sizeof(uint64_t));
if (send(sck, task, sizeof(task), 0) < 0) {
fprintf(stderr, "Send failed\n");
// pthread_exit(NULL);
exit(1);
}
char response[sizeof(uint64_t)];
if (recv(sck, response, sizeof(response), 0) < 0) {
fprintf(stderr, "Receive failed\n");
// pthread_exit(NULL);
exit(1);
}
memcpy(&data->result, response, sizeof(uint64_t));
close(sck);
// pthread_exit(NULL);
}
int main(int argc, char **argv) {
uint64_t k = -1;
uint64_t mod = -1;
char servers[255] = {'\0'};
while (true) {
int current_optind = optind ? optind : 1;
static struct option options[] = {
{"k", required_argument, 0, 0},
{"mod", required_argument, 0, 0},
{"servers", required_argument, 0, 0},
{0, 0, 0, 0}};
int option_index = 0;
int c = getopt_long(argc, argv, "", options, &option_index);
if (c == -1)
break;
switch (c) {
case 0: {
switch (option_index) {
case 0:
ConvertStringToUI64(optarg, &k);
break;
case 1:
ConvertStringToUI64(optarg, &mod);
break;
case 2:
memcpy(servers, optarg, strlen(optarg));
break;
default:
printf("Index %d is out of options\n", option_index);
}
} break;
case '?':
printf("Arguments error\n");
break;
default:
fprintf(stderr, "getopt returned character code 0%o?\n", c);
}
}
if (k == -1 || mod == -1 || !strlen(servers)) {
fprintf(stderr, "Using: %s --k 1000 --mod 5 --servers /path/to/file\n", argv[0]);
return 1;
}
// Чтение серверов из файла
FILE *file = fopen(servers, "r");
if (!file) {
fprintf(stderr, "Could not open servers file\n");
return 1;
}
unsigned int servers_num = 2;
struct Server *to = malloc(sizeof(struct Server) * servers_num);
int server_count = 0;
while (fscanf(file, "%s %d", to[server_count].ip, &to[server_count].port) != EOF) {
server_count++;
}
fclose(file);
pthread_t *threads = malloc(sizeof(pthread_t) * server_count);
struct ThreadData *thread_data = malloc(sizeof(struct ThreadData) * server_count);
uint64_t chunk_size = k / server_count;
for (int i = 0; i < server_count; i++) {
thread_data[i].server = to[i];
thread_data[i].begin = i * chunk_size + 1;
thread_data[i].end = (i == server_count - 1) ? k : (i + 1) * chunk_size;
thread_data[i].mod = mod;
thread_data[i].result = 1;
pthread_create(&threads[i], NULL, send_request, &thread_data[i]);
}
uint64_t total = 1;
for (int i = 0; i < server_count; i++) {
pthread_join(threads[i], NULL);
total = MultModulo(total, thread_data[i].result, mod);
}
printf("Final answer: %lu\n", (unsigned long)total);
free(threads);
free(thread_data);
free(to);
return 0;
}
server.c:
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <netinet/in.h>
#include <pthread.h>
#include <netinet/ip.h>
#include <sys/socket.h>
struct FactorialArgs {
uint64_t begin;
uint64_t end;
uint64_t mod;
};
uint64_t MultModulo(uint64_t a, uint64_t b, uint64_t mod) {
uint64_t result = 0;
a = a % mod;
while (b > 0) {
if (b % 2 == 1)
result = (result + a) % mod;
a = (a * 2) % mod;
b /= 2;
}
return result % mod;
}
uint64_t Factorial(const struct FactorialArgs *args) {
uint64_t ans = 1;
for (uint64_t i = args->begin; i <= args->end; i++) {
ans = MultModulo(ans, i, args->mod);
}
return ans;
}
void *ThreadFactorial(void *args) {
struct FactorialArgs *fargs = (struct FactorialArgs *)args;
uint64_t *result = malloc(sizeof(uint64_t));
*result = Factorial(fargs);
return result;
}
int main(int argc, char **argv) {
int tnum = -1;
int port = -1;
while (true) {
int current_optind = optind ? optind : 1;
static struct option options[] = {
{"port", required_argument, 0, 0},
{"tnum", required_argument, 0, 0},
{0, 0, 0, 0}};
int option_index = 0;
int c = getopt_long(argc, argv, "", options, &option_index);
if (c == -1)
break;
switch (c) {
case 0: {
switch (option_index) {
case 0:
port = atoi(optarg);
break;
case 1:
tnum = atoi(optarg);
break;
default:
printf("Index %d is out of options\n", option_index);
}
} break;
case '?':
printf("Unknown argument\n");
break;
default:
fprintf(stderr, "getopt returned character code 0%o?\n", c);
}
}
if (port == -1 || tnum == -1) {
fprintf(stderr, "Using: %s --port 20001 --tnum 4\n", argv[0]);
return 1;
}
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
fprintf(stderr, "Can not create server socket!");
return 1;
}
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons((uint16_t)port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
int opt_val = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val));
int err = bind(server_fd, (struct sockaddr *)&server, sizeof(server));
if (err < 0) {
fprintf(stderr, "Can not bind to socket!");
return 1;
}
err = listen(server_fd, 128);
if (err < 0) {
fprintf(stderr, "Could not listen on socket\n");
return 1;
}
printf("Server listening at %d\n", port);
while (true) {
struct sockaddr_in client;
socklen_t client_len = sizeof(client);
int client_fd = accept(server_fd, (struct sockaddr *)&client, &client_len);
if (client_fd < 0) {
fprintf(stderr, "Could not establish new connection\n");
continue;
}
while (true) {
unsigned int buffer_size = sizeof(uint64_t) * 3;
char from_client[buffer_size];
int read = recv(client_fd, from_client, buffer_size, 0);
if (!read)
break;
if (read < 0) {
fprintf(stderr, "Client read failed\n");
break;
}
if (read < buffer_size) {
fprintf(stderr, "Client send wrong data format\n");
break;
}
pthread_t threads[tnum];
struct FactorialArgs args[tnum];
uint64_t total = 1;
uint64_t begin = 0;
uint64_t end = 0;
uint64_t mod = 0;
memcpy(&begin, from_client, sizeof(uint64_t));
memcpy(&end, from_client + sizeof(uint64_t), sizeof(uint64_t));
memcpy(&mod, from_client + 2 * sizeof(uint64_t), sizeof(uint64_t));
fprintf(stdout, "Receive: %lu %lu %lu\n", (unsigned long)begin, (unsigned long)end, (unsigned long)mod);
uint64_t chunk_size = (end - begin + 1) / tnum;
for (uint32_t i = 0; i < tnum; i++) {
args[i].begin = begin + i * chunk_size;
args[i].end = (i == tnum - 1) ? end : (begin + (i + 1) * chunk_size - 1);
args[i].mod = mod;
if (pthread_create(&threads[i], NULL, ThreadFactorial, (void *)&args[i])){
printf("Error: pthread_create failed!\n");
return 1;
};
}
for (uint32_t i = 0; i < tnum; i++) {
uint64_t *result;
pthread_join(threads[i], (void **)&result);
total = MultModulo(total, *result, mod);
}
printf("Total: %lu\n", (unsigned long)total);
char buffer[sizeof(total)];
memcpy(buffer, &total, sizeof(total));
err = send(client_fd, buffer, sizeof(total), 0);
if (err < 0) {
fprintf(stderr, "Can't send data to client\n");
break;
}
}
shutdown(client_fd, SHUT_RDWR);
close(client_fd);
}
return 0;
}
servers.txt:
127.0.0.1 20001
127.0.0.1 20002
Командная строка:
./server --port 20001 --tnum 4
./server --port 20002 --tnum 4
./client --k 5 --mod 9 --servers servers.txt
CC = gcc
CFLAGS = -I. -lpthread
all: client server
client: client.o
$(CC) -o client client.o $(CFLAGS)
server: server.o
$(CC) -o server server.o $(CFLAGS)
client.o: client.c
$(CC) -c client.c $(CFLAGS)
server.o: server.c
$(CC) -c server.c $(CFLAGS)
clean:
rm -f *.o client server
multmodulo.h:
#ifndef MULTMODULO_H
#define MULTMODULO_H
#include <stdint.h>
uint64_t MultModulo(uint64_t a, uint64_t b, uint64_t mod);
#endif // MULTMODULO_H
multmodulo.c:
#include "multmodulo.h"
uint64_t MultModulo(uint64_t a, uint64_t b, uint64_t mod) {
uint64_t result = 0;
a = a % mod;
while (b > 0) {
if (b % 2 == 1)
result = (result + a) % mod;
a = (a * 2) % mod;
b /= 2;
}
return result % mod;
}
makefile:
CC = gcc
CFLAGS = -I. -lpthread
all: client server
client: client.o multmodulo.o
$(CC) -o client client.o multmodulo.o $(CFLAGS)
server: server.o multmodulo.o
$(CC) -o server server.o multmodulo.o $(CFLAGS)
client.o: client.c multmodulo.h
$(CC) -c client.c $(CFLAGS)
server.o: server.c multmodulo.h
$(CC) -c server.c $(CFLAGS)
multmodulo.o: multmodulo.c multmodulo.h
$(CC) -c multmodulo.c $(CFLAGS)
clean:
rm -f *.o client server