当我强行退出服务器(输入clt+c)时,客户端也会同时终止,有什么办法可以做到这一点吗



编写两个独立的C程序,一个用于TCP服务器(处理单个用户)和另一个用于客户端。

在服务器端-创建一个套接字并侦听某个特定端口以处理客户端要求

存在一个具有n行的默认文件,服务器应该能够以处理来自客户端的READX和WRITEX请求。

  1. 服务器进程应该标记从客户端接收到的字符串可能包含以下格式的READX或WRITEX请求-
    • READX k-从文件开始读取第k行,然后返回客户
    • WRITEX消息-将消息字符串附加到位于的文件末尾服务器,并将"SUCCESS!!"作为确认

在客户端-

  1. 客户端进程应该接受用户的输入,无论是READ还是在服务器端写入
  2. 然后,它启动到服务器的连接,并将查询转发到服务器
  3. 从服务器接收输出并将其显示给用户

我几乎已经处理了所有的错误处理。一切都在起作用。

  1. 我的第一个查询是,如果我强行终止服务器程序(例如,输入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 : %sn", 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 '' 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 terminatingn");
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 stringn"   );
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 : %sn", 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 connectn");
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("%sn",convert((struct sockaddr *)p->ai_addr));
printf("client: connecting to %sn", 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("%sn",buffer );
bzero(buffer, 255);
}
close(client_sockfd);
}

我不确定我是否正确阅读了您的代码,但在我看来,如果(客户端或服务器)读取了零字节,则不会产生任何消息读取(2)可以返回零:

返回值如果成功,则返回实际读取的字节数。在上面读取文件末尾时,返回零。否则,返回-1全局变量errno被设置为指示错误。

文件结尾不被视为错误。这是遥控器已关闭连接的正常指示,当程序终止时会自动发生这种情况。

因此,对于任何具有未完成读取操作(被阻止,等待来自对等端的数据)的进程,读取(2)将在对等端终止时返回零。如果您终止服务器,而客户端正在读取,则客户端将看到零字节读取,反之亦然。

您的客户端逻辑对这种情况没有任何特殊作用。你测试-1。如果不是-1,则在(空的)缓冲区中测试一堆东西。然后退出。

明确检查是否为零,并编写一条消息,说明服务器已关闭连接。我想你会看到客户并没有"自动终止"。它只是从末端掉下来。

您可以使用一个信号处理程序来检测Ctrl+C,然后您可以编写一个函数来向客户端发送关闭信号。Ctrl+C发送一个SIGINT信号。

#include <signal.h>
void sigintHandler(int sig_num) 
{ 
signal(SIGINT, sigintHandler); 
//Code here for Shutting Down Client
fflush(stdout); 
} 

你可以在这里阅读更多关于它的信息,如果你想处理那些太的信号,你可以对生成的任何信号进行处理

这应该可以解决您的第一个问题

相关内容

最新更新