2012-06-01 2 views
1

У меня проблема с домашней работой. Socket-программирование с доменом Unix
1. Клиент отправить имя файла на сервер
2. Сервер проверяет наличие файла, открывает и посылает дескриптор файла клиенту
3. Клиент открывает дескриптор файла и выводит на экран. platform = ubuntu 12.04. У меня проблема с клиентом. Неисправность Сегментация Error (ядро сбрасывали) на линии 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); 
} 

Client

#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); 
    } 
+1

Вы можете проверить перед строкой 'fd = * p', если' p == 0'. Похоже на разуплотнение нулевого указателя – maverik

+2

Первое, что вам нужно сделать, когда вы получаете аварийный сигнал или какой-либо другой, - запустить программу в отладчике. Это не только поможет вам определить местоположение аварии, но также позволит вам просмотреть переменные, чтобы помочь вам разобраться в причинах сбоя. –

+0

@maverik думаю. если проблема остается в p == 0. Это означает, что клиент не может получить файловый дескриптор от Sever. ты знаешь почему? –

ответ

0

Вам нужно чтобы проверить код ошибки, возвращенный recvmesg, прежде чем делать что-либо с данными, которые могут или не могут возвращены.

У вас нет гарантий, что recvmesg сообщите, что mh будет в работоспособном состоянии.

+0

Я проверил. Эта проблема не здесь –

0

Ошибка сегментации на *p означает, что p либо равен нулю, либо указывает на нераспределенную память.

Похоже, что p должен указывать внутри mh где-то. Сначала проверьте, что значение p перед сбоем находится между &mh и (char*)&mh + sizeof(mh).

4

Теоретически вы не можете делиться файловыми дескрипторами между процессами через сокеты TCP с процессами с разными адресными пространствами. Для этого вы можете использовать сокеты UNIX.

Если вы хотите обмениваться информацией между процессами (а не файловыми дескрипторами), вы можете использовать другие методы, такие как mmap, pipes, передача сообщений и т. Д.

Смежные вопросы