Socket编程的分段错误

时间:2012-06-01 07:58:58

标签: c linux

我有一个家庭作业问题。用Unix域编程插件  1.客户端将文件名发送到服务器
 2.服务器检查文件是否存在,打开,并将文件描述符发送到客户端
 3.客户端打开文件描述符并输出到屏幕。 platform = ubuntu 12.04。 我有客户端的问题。第fd = *p行上的错误分段错误(核心转储)(我已在客户端代码上标记)
这是我的代码

服务器

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdbool.h>
#include <signal.h>
#include <sys/wait.h>

#define SOCKNAME "sockunix"
bool ende = false;
void sigfkt(int signr){
    printf("SIGINT empfangen ...\n");
    ende = true;
}

int main(){
int fd, sockd, sockd2, rc, *p, sl;
FILE *fp;
struct sockaddr_un uxadr;
struct msghdr mh;
struct cmsghdr *cmp;
char ctrl[sizeof(struct cmsghdr)+10];
struct iovec iov[1];
char eab[100];
//bat dau khai bao
mh.msg_name = NULL;
mh.msg_namelen = 0;
mh.msg_iov = iov;
mh.msg_iovlen = 1;
mh.msg_control = ctrl;
mh.msg_controllen = sizeof(ctrl);
mh.msg_flags = 0;
cmp = CMSG_FIRSTHDR(&mh);
cmp->cmsg_len = CMSG_LEN(fd);
cmp->cmsg_level = SOL_SOCKET;
cmp->cmsg_type = SCM_RIGHTS;
p = (int *)CMSG_DATA(cmp);
// khoi tao socket
uxadr.sun_family = AF_UNIX;
strcpy(uxadr.sun_path, SOCKNAME);

sockd = socket(AF_UNIX, SOCK_STREAM, 0);
if(sockd<0){
    perror("socket");
    exit(1);
}

unlink(uxadr.sun_path);
sl = sizeof(uxadr);
rc = bind(sockd, (struct sockaddr*)&uxadr, sl);
if(rc<0){
    perror("bind");
    exit(2);
}

rc = listen(sockd, 10);
if(rc<0){
    perror("listen");
    exit(3);
}

sigset(SIGINT, sigfkt);
printf("Warte auf Client-Anforderungen ....\n"); //cho client ket noi toi
do{ 
    sockd2 = accept(sockd, 0, 0);
    if(ende)
        break;
    if(sockd2<0){
        perror("accept");
        exit(4);
    }

    iov[0].iov_base = eab;
    iov[0].iov_len = sizeof(eab);
    rc = recvmsg(sockd2,&mh,0); //nhan File name tu client
    if(rc<0){
        perror("recvmsg");
        exit(5);
    }
    printf("%s\n",eab);
    if(rc>0){
        fp = fopen(eab,"r");// kiem tra xem file ton tai ko?
        if(fp==NULL){
            printf("file not existiert\n");
            eab[0]=1; // thong bao cho client file ko ton tai
        }
        else{
            fd = fileno(fp); // lay File descriptor
            eab[0]=2; // thong bao cho client file ton tai
            *p = fd; //gan File descriptor vao cau truc dieu khien
        }
    }
printf("fd=%d\n",*p);
    rc = sendmsg(sockd2,&mh,0); // guoi thong bao va File descriptor den client
    if(rc<0){
        perror("sendmsg");
    }
    close(sockd2);
}while(!ende);

close(sockd);
unlink(uxadr.sun_path);
}

客户端

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/un.h>
    #include <stdbool.h>
    #include <signal.h>
    #include <sys/wait.h>

    #define SOCKNAME "sockunix"

    int main(int argc, char *argv[]){
    int  fd = 0, sockd, rc, *p, sl;
    FILE *fp;
    struct sockaddr_un uxadr;
    struct msghdr mh;
    struct cmsghdr *cmp;
    char ctrl[sizeof(struct cmsghdr)+10];
    struct iovec iov[1];
    char eab[100],fname[100];
    //bat dau khai bao
    mh.msg_name = NULL;
    mh.msg_namelen = 0;
    mh.msg_iov = iov;
    mh.msg_iovlen = 1;
    mh.msg_control = ctrl;
    mh.msg_controllen = sizeof(ctrl);
    mh.msg_flags = 0;
    cmp = CMSG_FIRSTHDR(&mh);
    cmp->cmsg_len = CMSG_LEN(fd);
    cmp->cmsg_level = SOL_SOCKET;
    cmp->cmsg_type = SCM_RIGHTS;
    p = (int *)CMSG_DATA(cmp);
    //khoi tao socket
    uxadr.sun_family = AF_UNIX;
    strcpy(uxadr.sun_path, SOCKNAME);

    sockd = socket(AF_UNIX, SOCK_STREAM, 0);
    if(sockd<0){
        perror("socket");
        exit(1);
    }

    sl = sizeof(uxadr);
    rc = connect(sockd, (struct sockaddr *)&uxadr, sl);
    if(rc<0){
        perror("connect");
        exit(2);
    }

    if(argc>=2){ // dua File name vao tu dong lenh
        sprintf(fname,"%s",argv[1]);
    }
    else{// neu chua co File name thi bat dau nhap file name vao
        printf("Bitte Filename eingeben\n");
        fflush(stdin);
        gets(fname); 

    }

    iov[0].iov_base = fname;
    iov[0].iov_len = strlen(fname)+1;
    rc = sendmsg(sockd, &mh, 0); // guoi filename sang server
    if(rc<0){
        perror("sendmsg");
        exit(3);
    }

    iov[0].iov_base = eab;
    iov[0].iov_len = sizeof(eab);
    rc = recvmsg(sockd, &mh, 0); // nhan thong bao va File descriptor tu server
    cmp = CMSG_FIRSTHDR(&mh);
    p = (int *)CMSG_DATA(cmp);
    if(rc<0){
        perror("recvmsg");
        exit(4);
    }


    switch(eab[0]){// kiem tra thong bao
        case 1:// file khong ton tai
            printf("File ist nicht existiert!\n");
            break;
        case 2:// file ton tai
            printf("File ist existiert. Filedeskriptor ist bereits zu verwandel!\n");


FAULT ================>  fd = *p; //fault here with GDB debug


            printf("fd=%d\n",fd);
            fp = fdopen(fd,"r");
            if(fp=NULL)
                printf("fehler fd\n");
            printf("Fileinhalt ausgeben\n");
            printf("=============================================\n");
            while(fread(eab,100,1,fp)>0)
                printf("%s", eab);
            printf("=============================================\n");
            fclose(fp);
            break;
    }
    close(sockd);
    }

3 个答案:

答案 0 :(得分:4)

理论上,您不能通过TCP套接字与具有不同地址空间的进程在进程之间共享文件描述符。为此,您可以使用UNIX套接字。

如果要在进程(而不是文件描述符)之间共享信息,可以使用其他技术,如mmappipes,消息传递等。

答案 1 :(得分:0)

您需要检查recvmesg返回的错误代码,然后才能对可能或可能未返回的数据执行任何操作。

recvmesg返回mh处于可用状态的错误时,无法保证。

答案 2 :(得分:0)

*p上的分段错误意味着p为零或指向未分配的内存。

看起来p应该指向某个地方。首先检查崩溃前的p值是否在&mh(char*)&mh + sizeof(mh)之间。