微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 FIFO 管道和服务器和客户端之间的分叉通信的分段错误核心转储

如何解决使用 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 举报,一经查实,本站将立刻删除。