2012-06-01 43 views
1

我有一個作業問題。套接字編程與Unix域
1.客戶端發送文件名,服務器
2.服務器檢查該文件存在,將打開,併發送文件描述符客戶
3.客戶端打開一個文件描述符並輸出到屏幕上。 platform = ubuntu 12.04。 我與客戶有問題。錯誤段錯誤(核心轉儲)上線fd = *p(我已經標上的客戶端代碼)
這是我的代碼Socket編程中的分段錯誤

服務器

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

如果'p == 0',你可以在行'fd = * p'之前檢查嗎?看起來像空指針取消引用 – maverik

+2

當你遇到崩潰或任何類型時,你應該做的第一件事是在調試器中運行該程序。這不僅可以幫助您查明崩潰的位置,還可以讓您檢查變量以幫助您找出崩潰的原因。 –

+0

@maverik我這麼認爲。如果問題留在p == 0。這意味着客戶端無法從Sever接收文件描述符。你知道爲什麼? –

回答

0

您需要在對數據做任何事情之前檢查由recvmesg返回的錯誤代碼,它可能會或可能不會已經回來了。

無法保證當recvmesg返回mh將處於可用狀態的錯誤。

+0

我查過了。這個問題並不在於此 –

0

*p上的段錯誤表示p爲零或指向未分配的內存。

它看起來像p應該是指向內部某處。首先檢查崩潰前p的值是在&mh(char*)&mh + sizeof(mh)之間。

4

理論上,不能在TCP套接字上的進程之間共享具有不同地址空間的進程的文件描述符。爲了做到這一點,你可以使用UNIX套接字。

如果要共享進程間的信息(不是文件描述符),可以使用其他技術,如mmap,pipes,消息傳遞等。