如何解决使用 FIFO 管道和服务器和客户端之间的分叉通信的分段错误核心转储
我正在编写一个项目,您可以在一个终端中启动服务器,而在作为客户端的其他终端中,您可以使用 FIFO 管道将消息从一个用户发送到另一个用户。服务器创建从客户端读取消息的 FIFO 管道。客户端创建 FIFO 管道以从服务器读取消息。
在一个终端中,我输入 ./projectname --start
来启动服务器,而在客户端中,我输入 ./projectname --login nickname
。当我关闭客户端时,我的服务器收到分段错误(核心转储)错误消息。我试图以我知道的所有可能的方式摆脱这个 x 小时。如何修复?
我还尝试使用 void verifyloginclient(char *login)
函数注册用户,但是父进程无法从子进程接收信息并且陷入无限的 while(1)
向服务器发送一些消息,该消息也会因分段错误而使服务器崩溃,因此对其进行了评论暂时。
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
char userlist[10][30];
int succesfulllogin = 1;
void handler(int signum){
pid_t pid;
pid = wait(NULL);
succesfulllogin = 0;
printf("Parent kNows child %d finished\n",(int)pid);
printf("Parent ending...\n");
}
void sig_handler_parent(int signum){
printf("signal response from child!\n");
succesfulllogin = 0;
exit(0);
}
void sig_handler_child(int signum){
printf("signal from parent\n");
succesfulllogin = 0;
exit(0);
}
void verifyloginclient(char *login)
{
int fd;
char buf[256];
char buf2[256];
snprintf(buf,sizeof buf,"%s%s","fifopipes/","serwer.fifo");
if((fd = open(buf,O_WRONLY)) == -1){
perror("openFdloginclient");
exit(EXIT_FAILURE);
}
snprintf(buf2,sizeof buf2,"%s%s%s",login," /login ",login);
if((write(fd,buf2,strlen(buf2))) == -1){
perror("writeloginclient");
}
close(fd);
}
int verifyloginserwer(char *login)
{
// check if login is on the userlist
int flagcmp = -1;
int x;
int indeks=0;
for(int i=0;i<10;i++){
x = strcmp(&userlist[i][0],login);
if(x==0){
flagcmp = i;
}
}
if(flagcmp == -1){ //if it doesnt exist we add him to first free slot
for(int i=0;i<10;i++){
if(userlist[i][0]=='\0'){
strcpy(userlist[i],login);
printf("userlist: %s\n",userlist[i]);
succesfulllogin = 1;
break;
}
else{
indeks++;
}
}
}
else if(flagcmp != -1 || indeks==10){
fprintf(stderr,"loggin error!\n");
succesfulllogin = 0;
return 2;
}
return 0;
}
int splitstring(char *source,int desiredlength,char **s1,char **s2)
{
int len;
len = strlen(source);
if (desiredlength > len)
return(0);
*s1 = (char *) malloc(sizeof(char) * desiredlength);
*s2 = (char *) malloc(sizeof(char) * len-desiredlength+1);
if(s1 ==NULL || s2 == NULL)
return 0;
strncpy(*s1,source,desiredlength);
strncpy(*s2,source+desiredlength,len-desiredlength);
return(1);
}
void startserwer()
{
int fdserwer;
int fdanuluj;
int fd;
char readbuf[80];
int read_bytes;
char buf[256]; //pipe server
char buf2[256]; //pipe client
char buf3[256]; // message to client
for(int i=0;i<10;i++){ // declare userlist
userlist[i][0] = '\0';
}
snprintf(buf,"serwer.fifo");
umask(0);
if(mkfifo(buf,0777) == -1){
perror("mkfifoserwer");
exit(EXIT_FAILURE);
}
while(1){
if((fdserwer = open(buf,O_CREAT | O_RDONLY))== -1){
perror("openFdserwer");
exit(EXIT_FAILURE);
}
if((read_bytes = read(fdserwer,&readbuf,sizeof(readbuf)))== -1){
perror("readbytes");
}
else{
readbuf[read_bytes] = '\0';
//SENDER LOGIN
char senderlogin[80];
strcpy(senderlogin,readbuf);
char *token = strtok(senderlogin," ");
printf("%s\n",token);
strcpy(senderlogin,token);
int b;
char *loginnadawcy;
char *resztakomendy;
b = splitstring(readbuf,(int) strlen(token)+1,&loginnadawcy,&resztakomendy);
if(b!=1){
printf("error in command\n");
}
else{
loginnadawcy[strlen(token)]='\0';
//COMMAND NAME AFTER SLASH /
char command[80];
strcpy(command,readbuf);
token = strtok(NULL," ");
printf("%s\n",token);
strcpy(command,token);
int a;
char *komenda;
char *reszta;
a = splitstring(resztakomendy,(int)strlen(token)+1,&komenda,&reszta);
if(a!=1){
printf("error\n");
}
else{
komenda[strlen(token)]='\0';
if(strcmp(komenda,"/login")==0){
if(verifyloginserwer(senderlogin)==2){
//open client pipe
snprintf(buf2,senderlogin,".fifo");
if((fdanuluj = open(buf2,O_WRONLY)) == -1){
perror("openFdanuluj");
exit(EXIT_FAILURE);
}
//SEND MESSAGE TO CLIENT
snprintf(buf3,sizeof buf3,"serwer ","end");
if((write(fdanuluj,buf3,strlen(buf3))) == -1){
perror("writeFdanuluj");
}
close(fdanuluj);
}
}
else if(strcmp(komenda,"/w")==0){
//RECEIVER LOGIN
char receiverlogin[80];
token = strtok(NULL," ");
printf("%s\n",token);
strcpy(receiverlogin,token);
int r;
char *login;
char *message;
r = splitstring(reszta,&login,&message);
if(r!=1){
printf("error\n");
}
else{
//RECEIVE informatION
login[strlen(receiverlogin)]='\0';
printf("from %s to %s: %s and length is %d \n",message,(int)strlen(message));
//OPEN CLIENT PIPE
snprintf(buf2,receiverlogin,".fifo");
if((fd = open(buf2,O_WRONLY))== -1){
perror("openFd");
exit(EXIT_FAILURE);
}
//SEND MESSAGE TO CLIENT
snprintf(buf3," ",message);
if( (write(fd,strlen(buf3) )) == -1){
perror("writeopenfd");
}
close(fd);
}
}
}
}
}
close(fdserwer);
}
unlink(buf);
}
void clientchild(char *login)
{
int fd;
char readbuf[80];
int read_bytes;
char buf[256];
snprintf(buf,".fifo");
umask(0);
if(mkfifo(buf,0777) == -1){
perror("mkfifoclient");
exit(EXIT_FAILURE);
}
while(1){
if((fd = open(buf,O_CREAT | O_RDONLY)) == -1){
perror("openFdchild");
exit(EXIT_FAILURE);
}
if((read_bytes = read(fd,sizeof(readbuf))) == -1){
perror("readfdchild");
}
else{
readbuf[read_bytes] = '\0';
//SENDER LOGIN
char nickname[80];
strcpy(nickname,readbuf);
char * token = strtok(nickname," ");
//printf("%s\n",token);
int r;
char *login;
char *message;
r = splitstring(readbuf,&message);
if(r!=1){
printf("blad\n");
}
else{
login[strlen(token)]='\0';
if(strcmp(login,"serwer")==0 && strcmp(message,"end")==0){
printf("Login error. Closing...\n");
close(fd);
break;
}
printf("%s: %s and length is %d \n",(int)strlen(message));
close(fd);
//printf("Received string: \"%s\" and length is %d \n",readbuf,(int)strlen(readbuf));
}
//free(login);
//free(message);
}
}
unlink(buf);
}
void clientparent(char *login)
{
signal(SIGQUIT,sig_handler_parent);
int fd;
int stringlen;
char readbuf[80];
char buf[256];
char buf2[256];
snprintf(buf,"serwer.fifo");
printf("FIFO_CLIENT: Send messages infinitely\n");
while(1){
if((fd = open(buf,O_WRONLY)) == -1){
perror("openFdparent");
exit(EXIT_FAILURE);
}
//printf("Enter string: ");
fgets(readbuf,sizeof(readbuf),stdin);
stringlen = strlen(readbuf);
readbuf[stringlen - 1] = '\0';
snprintf(buf2,readbuf);
if(strlen(login)+1 == strlen(buf2)){
printf("Error\n");
break;
}
else{
if((write(fd,strlen(buf2))) == -1){
perror("writeparent");
}
printf("Sent string: \"%s\" and string length is %d \n",(int)strlen(buf2));
}
}
close(fd);
}
void splitclient(char *login)
{
printf("login: %s\n",login);
pid_t pid = fork();
printf("fork returned: %d\n",(int) pid);
//signal(SIGCHLD,handler);
if (pid < 0){
perror("Fork Failed");
}
else if (pid == 0){
signal(SIGQUIT,sig_handler_child);
printf("I am the child with pid %d\n",(int) getpid());
char buf[256];
snprintf(buf,"%s%d","Child ",(int) getpid());
//kod dziecka
clientchild(login);
//kill(getppid(),SIGQUIT);
exit(0);
}
else{
// We must be the parent
printf("I am the parent,waiting for child to end \n");
//kod rodzica
clientparent(login);
pid_t childpid = wait(NULL);
printf("Parent kNows child %d finished\n",(int)childpid);
printf("Parent ending...\n");
}
}
int main(int argc,char **argv)
{
while(1)
{
int c;
int option_index = 0;
static struct option long_options[] =
{
{"start",no_argument,NULL,'s'},{"login",required_argument,'l'},{0,0}
};
c = getopt_long (argc,argv,"sl:",long_options,&option_index);
if (c == -1)
break;
switch (c)
{
case 's':
printf("start server\n");
startserwer();
break;
case 'l':
printf("login with option %s \n",optarg);
//verifyloginclient(optarg);
splitclient(optarg);
break;
case '?':
break;
default:
abort();
}
}
if (optind < argc)
{
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ",argv[optind++]);
putchar ('\n');
}
return 0;
}
解决方法
来自 startServer()
中代码中的这段:
if((read_bytes = read(fdserwer,&readbuf,sizeof(readbuf)))== -1){
perror("readbytes");
}
else{
:
char *token = strtok(senderlogin," ");
:
strcpy(senderlogin,token);
b = splitstring(readbuf,(int)
strlen(token)+1,&loginnadawcy,&resztakomendy);
您没有验证 token
是否为非 NULL
指针后标记化。在子进程退出的情况下,read()
将返回 0(而不是 -1 作为失败),指示 EOF,如 man 所述:
返回值
成功时,返回读取的字节数(零表示
文件结束),
因此 senderlogin
缓冲区将为空并且不会产生任何标记。您需要考虑这种情况并进行适当的空检查。添加空校验将导致服务器程序正常退出。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。