Напишите две отдельные программы на C, одну для TCP-сервера (обрабатывает запрос для
один пользователь) и другой для клиента.
На стороне сервера
Создает сокет и прослушивает определенный порт для обработки клиента
запрос.
Существует файл по умолчанию, имеющий n строк, и сервер должен быть в состоянии
обработать READX и WRITEX запрос от клиента.
- Процесс сервера должен маркировать строку, полученную от клиента, которая
может содержать запрос READX или WRITEX в следующем формате:
- READX k- прочитать k-ю строку из начала файла и вернуться к
клиент.
- WRITEX msg - добавить строку msg в конец файла, представленного в
сервер и верните «УСПЕХ !!» клиенту как
подтверждение.
На стороне клиента-
- Клиентский процесс должен принимать данные от пользователя, читать или
НАПИСАТЬ на стороне сервера.
- Затем он инициирует соединение с сервером и перенаправляет запрос на сервер.
- Получает выходные данные с сервера и отображает их для пользователя.
Я почти обработал все ошибки. Все работает.
- Мой первый запрос, если я принудительно уничтожаю серверную программу (например, путем ввода clt + c), я хочу, чтобы клиентская программа была завершена одновременно. как я могу это сделать?
- 2-й запрос: когда я принудительно убиваю клиента, моя серверная программа автоматически завершается. Но я не понимаю, почему это происходит? В общем-то. этого не происходит. Я не нахожу, какая строка моего кода делает это возможным.
Код сервера:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<arpa/inet.h>
#include<unistd.h>
#define MYPORT "5000"
#define BACKLOG 3
char space[] = " ";
/*this funtion is counting total no of line present in input.txt file
whenever it is called */
int count_line()
{
FILE *ptr = fopen("input.txt", "r");
char * line = NULL;
int i = 0;
size_t count =0;
if (ptr == NULL)
{
perror("error: line no 21");
}
while(getline(&line,&count, ptr) > 0)
{
i++;
}
fclose(ptr);
return i;
}
/* This funtion will write the message what is given by client at the
end of the file */
int write_instruction(char *buffer,int max_length)
{
char final[255];
FILE *fp = fopen("input.txt", "a");
if(fseek(fp, 0, SEEK_END) != 0)
{
perror("fseek:error");
exit(EXIT_FAILURE);
}
if (count_line() == 250)
{
sprintf(final,"%d%s%s",count_line() +1, space, buffer);
}
else
sprintf(final,"%s%d%s%s","\n",count_line() +1, space, buffer);
fputs(final, fp);
fclose(fp);
return (1);
}
/* This function will fetch the exact line from input.txt what is instructed by READX in client and will return to client */
void read_instruction(int line_no, int max_length, int server_new_fd)
{
ssize_t no_read_byte;
/*error checking , if you enter out of bound line no*/
if ((line_no > count_line()) || (line_no <1))
{
if( ( no_read_byte = write(server_new_fd, "you are entering out of bound line no: TRY AGAIN", strlen("you are entering out of bound line no: TRY AGAIN")+1)) == -1)
{
perror("write:error");
exit(EXIT_FAILURE);
}
return;
}
char *line = NULL, final[max_length];
size_t count =0;
FILE *stream = fopen("input.txt", "r");
if (stream == NULL)
exit(EXIT_FAILURE);
for (int i = 0;i < line_no; ++i)
{
if(getline(&line, &count, stream) == -1)
{
perror("getline: error");
}
}
if( ( no_read_byte = write(server_new_fd, line, strlen(line)+1)) == -1)
{
perror("write:error");
exit(EXIT_FAILURE);
}
free(line);
fclose(stream);
return ;
}
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main()
{
int status, server_sockfd, yes = 1, server_new_fd;
struct addrinfo hints, *ref, *p;
struct sockaddr_storage addr;
struct sockaddr_in m;
struct sockaddr_in6 n;
socklen_t addrlen;
ssize_t no_read_byte;
size_t count = 1024;
char ip_str[INET6_ADDRSTRLEN], buffer[1024], *readx, *writex;
memset(&hints, 0, sizeof hints);/* setting all bits of hints 0;*/
/* AF_UNSPEC mean any address family */
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_PASSIVE;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
if ( (status = getaddrinfo(NULL, MYPORT, &hints, &ref)) != 0)
{
fprintf(stderr, "getaddrinfo : %s\n", gai_strerror(status));
return 2;
}
for ( p = ref; p != NULL; p = p->ai_next)
{
/*creating socket where passing ai_family , ai_socktype, ai_protocol as domain, type, protocol.
And chhecking one by one struct addrinfo from list returned by getaddrinfo(), to get first successful socket descriptor.*/
if ( (server_sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("socket:error");
continue;
}
if (setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (int)) == -1)
{
perror("setsockopt : error");
exit(1);
}
if (bind(server_sockfd, p->ai_addr, p->ai_addrlen) == -1)
{
perror("bind : error");
close(server_sockfd);
continue;
}
/* I am getting out of this for loop because I already got successful socket fd, and successful binding.
I don't need to traverse the list anymore.
*/
break;
}
freeaddrinfo(ref);// I am done with struct addrinfo list.
/* I am listening here.*/
if (listen(server_sockfd, BACKLOG) == -1)
{
perror("listen : error");
exit(1);
}
printf("server: waiting for connection...........\n");
addrlen = sizeof(addr); /* If there are any client trying to connect, I accept here its connect request. */
if( (server_new_fd = accept(server_sockfd, (struct sockaddr *)&addr, &addrlen)) == -1)
{
perror("accept: error");
exit(EXIT_FAILURE);
}
inet_ntop(addr.ss_family, get_in_addr((struct sockaddr *)&addr), ip_str, sizeof ip_str);
printf("Server : %s is connected .\n", ip_str);
int i=0;
close(server_sockfd); /* WE are here just hanldling one client, so we do need to listen anymore. so we are closing server_sockfd */
while(1)
{
memset(&buffer, 0, 1024); /* Begining of every loop, we shall set '\0' to every byte of buffer */
/*we read here first time for every loop from server_new_fd and save it into buffer*/
if( (no_read_byte = read(server_new_fd, &buffer, count)) == -1)
{
perror("read failed");
exit(EXIT_FAILURE);
}
writex = buffer;
/*we are checking error here. when you will give just empty string, that will be detected here*/
if( (readx = strtok_r( writex, " ", &writex)) == NULL)
{
if( ( no_read_byte = write(server_new_fd, "you are entering invalid input", strlen("you are entering invalid input")+1) == -1))
{
perror("write:error");
exit(EXIT_FAILURE);
}
continue;
}/* here we are checking for shutdown condition . if you want to shutdown just enter -1*/
else if (strcmp(readx, "-1") == 0)
{
printf("we are terminating\n");
if( (no_read_byte = write(server_new_fd,"-1", strlen("-1")+1) ) == -1)
{
perror("write: error");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
/* if you enter just READX or WRITEX , then that will be detected here. */
else if ((atoi(writex) == 0) && (strcmp(readx, "READX") ==0) )
{
if( ( no_read_byte = write(server_new_fd, "you are entering invalid input", strlen("you are entering invalid input")+1)) == -1)
{
perror("write:error");
exit(EXIT_FAILURE);
}
continue;
}
else if ((writex[0] == 0) && (strcmp(readx, "WRITEX") ==0 ))
{
if( ( no_read_byte = write(server_new_fd, "you are entering invalid input", strlen("you are entering invalid input")+1)) == -1)
{
perror("write:error");
exit(EXIT_FAILURE);
}
continue;
}
/* this for READX formatted instruction */
else if( strcmp(readx, "READX") ==0)
{
char * str = strtok_r( writex, " ", &writex);
if (atoi(writex) != 0)
{
/* if you enter like READX 12 34 45, that will be detected here */
if( ( no_read_byte = write(server_new_fd, "you are entering invalid input", strlen("you are entering invalid input")+1)) == -1)
{
perror("write:error");
exit(EXIT_FAILURE);
}
continue;
}
else /* This for correct formatted READX instruction */
{
printf("Client is instructing to read and return line.\n");
read_instruction(atoi(str), 255, server_new_fd);
}
} /* this for correct WRITEX instruction */
else if (strcmp(readx, "WRITEX") ==0)
{
printf("Client is instructing to append given string to end of the file.\n");
if(write_instruction(writex, 255) == 1)
{
if( (no_read_byte = write(server_new_fd,"SUCCESS!!", strlen("SUCCESS!!")+1) ) == -1)
{
perror("write: error");
exit(EXIT_FAILURE);
}
}
}
else /* this for all other invalid error */
{
if( ( no_read_byte = write(server_new_fd, "you are entering invalid input 1", strlen("you are entering invalid input 1 ")+1)) == -1)
{
perror("write:error");
exit(EXIT_FAILURE);
}
continue;
}
}
close(server_new_fd);
}
код клиента:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<arpa/inet.h>
#include<unistd.h>
#define MYPORT "5000"
void *convert(struct sockaddr *sa)
{
if ( sa->sa_family == AF_INET)
return &(((struct sockaddr_in *)sa)->sin_addr);
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "you are entering wrong number of string\n" );
exit(EXIT_FAILURE);
}
struct addrinfo hints, *ref, *p;
int status, client_sockfd, yes = 1;
ssize_t no_read_byte;
size_t count=1024;
struct sockaddr_storage addr;
char ip_str[INET6_ADDRSTRLEN], buffer[1024];
memset(&hints, 0, sizeof hints);
if ( (status = getaddrinfo(argv[1], MYPORT, &hints, &ref)) != 0)
{
fprintf(stderr, "getaddrinfo : %s\n", gai_strerror(status));
return 2;
}
for (p = ref;p != NULL; p = p->ai_next)
{
if ( (client_sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("client_socket: error");
continue;
}
if ( (connect(client_sockfd, p->ai_addr, p->ai_addrlen)) == -1)
{
perror("connect: error");
close(client_sockfd);
continue;
}break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
exit(EXIT_FAILURE);
}
//inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), ip_str, sizeof ip_str);
inet_ntop(p->ai_family, convert((struct sockaddr *)p->ai_addr), ip_str, sizeof ip_str);
//printf("%s\n",convert((struct sockaddr *)p->ai_addr));
printf("client: connecting to %s\n", ip_str);
freeaddrinfo(ref);
while(1){
printf("please enter the instruction: ");
gets(buffer);
if ((no_read_byte = write(client_sockfd, buffer, strlen(buffer)+1)) == -1)
{
perror("write:error");
exit(EXIT_FAILURE);
}
bzero(buffer, 255);
if((no_read_byte = read(client_sockfd, buffer, 255)) == -1)
{
perror("read:error");
exit(EXIT_FAILURE);
}
else if (strcmp(buffer, "-1") == 0)
{
exit(EXIT_SUCCESS);
}
else
printf("%s\n",buffer );
bzero(buffer, 255);
}
close(client_sockfd);
}