2013-03-13 59 views
0

您好我目前正在編寫一個UNIX程序中的C程序來模擬一個套接字停止&等待協議的學校。當我在命令行中輸入4個參數時,我不斷收到分段錯誤。如果我輸入更多或更少,那麼我得到正確的錯誤。如果有人可以幫助它,將不勝感激。提前致謝。在UNIX停止和等待協議分段故障

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <errno.h> 
#include <stdlib.h> 
#include <strings.h> 

#define SERVER_PORT 6500 
#define MAX_LINE 256 

int 
main(int argc, char * argv[]) 
{ 
     FILE *fp; 
     struct hostent *hp; 
     struct sockaddr_in sin, client; 
     char *host; 
     char ack[MAX_LINE], buf[MAX_LINE], fname[MAX_LINE]; 
     int s, i, rnum, drop; 
     int8_t current, last = -1; 
     int rval, slen, NFrames, len; 

     long LenFile; 
     struct timeval rectime; //The struct timeval structure represents an elapsed time 
     struct timeval zone; 

     if (argc==4){ 
       host=argv[1]; 
     } 
     else { 
      fprintf(stderr, "usage: simplex-talk host\n"); 
      //fprintf(stderr, "hello"); 
       exit(1); 
     } 

     if (!hp) { 
       fprintf(stderr, "simplex-talk: unknown host: %s\n", host); 
       exit(1); 
     } 

     bzero((char *)&sin, sizeof(sin)); 
     sin.sin_family = AF_INET; 
     bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 
     sin.sin_port=htons(SERVER_PORT); 

     if((s=socket(PF_INET, SOCK_DGRAM,0)) < 0){ 
       perror("simplex-talk; socket"); 
       exit(1); 
     } 

     // create file request 
     sprintf(buf, "%s\0", argv[3]); 

     if ((rval=sendto(s,buf,sizeof(buf),0,(struct sockaddr *)&client,sizeof(client)))< 0) { 
printf("sjkdfj"); 
perror("writing on datagram socket"); 
     } 
     system("date"); 
     printf("Sent request for file %s at time = %ld %ld\n", argv[3], rectime.tv_sec, rectime.tv_usec); 

     bzero(ack,sizeof(ack)); 
     slen = sizeof(client); 

    buf[MAX_LINE-1] = '\0'; 
    len = strlen(buf) + 1; 
     //request to send, waiting.... 

     while ((rval = recvfrom(s,ack,sizeof(ack),0,(struct sockaddr *)&client,&slen))<0){ 
       perror("receiver recvfrom"); 
       printf(stderr, "hhhhhhhh"); 
} 
      //get time 
     if (gettimeofday(&rectime, &zone) < 0) { 
       perror("getting time"); 
       exit(1); 
     } 
     if(ack[0] == '0'){ 
       printf("Received file not found, time = %ld %ld, File = \"%s\"\n", rectime.tv_sec, rectime.tv_usec, fname); 
     } 
     if(ack[0] == '1') { 
       char ch[MAX_LINE]; 
       int i, j; 
       for(i=2, j=0; ack[i] != ' '; i++, j++){ 
         ch[j] = ack[i]; 
       } 
       ch[i++] = '\0'; 
       LenFile=atoi(ch); 
       for(j=0; ack[i] && ack[i] != '.'; i++, j++){ 
         fname[j] = ack[i]; 
       } 
       fname[i++] = '\0'; 
       strcat(fname, "client.txt"); 
       NFrames = LenFile/MAX_LINE + (LenFile % MAX_LINE == 0 ? 0:1); 
       printf("Received, ack sent, time = %ld %ld\nfname = \"%s\"\n", LenFile = "%d\n", rectime.tv_sec, rectime.tv_usec, fname, LenFile); 

       //file I/O (reads) 
       fp=fopen(fname, "w"); 
       if(fp==NULL){ 
         perror("Opening File for Writing"); 
         exit(1); 
       } 
       printf("Opening File %s for writing\n", fname); 
       drop = 0; 

       for(i=0; i < NFrames;){ 
         bzero(ack,sizeof(ack)); 
         while ((rval = recvfrom(s,ack,sizeof(ack),0,(struct sockaddr *)&client,&slen))<0){ 
           perror("receiver recvfrom"); 
         } 
//get time 
         if (gettimeofday(&rectime, &zone) < 0) { 
           perror("getting time"); 
           exit(1); 
         } 
         current = ack[0]; 
         if(current == last) { 
           printf("Duplicate frame %d received\n", last); 
           continue; 
         } 
         printf("Recieved Frame #%d at time = %ld %ld\n\nContent:\n%s\n", current, rectime.tv_sec, rectime.tv_usec, ack+1); 
         fputs(ack+1, fp); 

         //creating ack 
         bzero(buf,sizeof(buf)); 
         sprintf(buf, "%c%s\0", current, "ackp"); 

         //25% chance of loss is to call random() 
         rnum = random(); 
         if((rnum%4) != 0) { 
           // get time 
           if (gettimeofday(&rectime, &zone) < 0) { 
             perror("getting time"); 
             exit(1); 
           } 
           if ((rval=sendto(s,buf,sizeof(buf),0,(struct sockaddr *)&client,sizeof(client))) < 0) { 
           perror("writing on datagram socket"); 
           }else{ 
             i++; 
             last = current; 
             printf("Sent Received Packet ACK for Frame %d at time = %ld %ld\n", current, rectime.tv_sec, rectime.tv_usec); 
           } 
         }else{ 
           drop++; 
         } 
       } 
       printf("Total Number of dropped frames is %d\n", drop); 
       //get time 
       if (gettimeofday(&rectime, &zone) < 0) { 
         perror("getting time"); 
         exit(1); 
       } 
       fclose(fp); 
       printf("Closing file for writing at time = %ld %ld\n", rectime.tv_sec, rectime.tv_usec); 
     } 
     //get time 
     if (gettimeofday(&rectime, &zone) < 0) { 
       perror("getting time"); 
       exit(1); 
     } 
     printf("Closing Socked %d for File \"%s at time = %ld %ld\n", ntohs(client.sin_port), fname, rectime.tv_sec, rectime.tv_usec); 
     close(s); 
} 
+1

你檢查'hp'(就像這樣:'if(!hp)'),但你永遠不會初始化任何'hp'。這是一個指針,它指向誰知道在哪裏?換句話說,它是垃圾。垃圾不可能是'NULL'。所以你繼續往下走...... * bam!* – 2013-03-13 21:10:33

+0

不確定你的意思。 是不是hp被初始化爲代碼中的一個結構?如果主機名不正確,它會返回錯誤。請注意,我正在遠程通過學校的虛擬機執行此操作。 – 2013-03-13 21:12:32

+1

您可以向我們展示一個[簡短,自包含,可編譯的示例](http://sscce.org/)?您發佈的代碼(a)不會編譯,並且(b)與未使用的變量混雜在一起,可能與您實際的參數計數和變量初始化問題無關。 – pilcrow 2013-03-13 21:13:24

回答

0

第一問題是在這裏:

bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 

哪裏hp點?這是一個你沒有初始化的指針,它指向內存中的一些隨機區域。在內存中訪問一些不屬於你的隨機區域是不好的。不要這樣做。

+0

好吧,我編輯它指向我認爲的東西。 if(argc == 4)host = argv [1]; \t \t hp = gethostbyname(host); } – 2013-03-13 21:26:16

+0

不錯!不是很好(如果你沒有設置它,你仍然不會給'hp'一個合理的默認值,但是如果你退出了,那麼我們不要挑剔),但並不壞。所以...現在...告訴...會發生什麼?不要讓我們陷入懸念。 – 2013-03-13 21:28:00

+0

好吧沒有分割錯誤!哇噢!但還沒有離開球場。現在我得到一個數據報套接字錯誤。 寫在數據報套接字:無效的參數 週三年03月13 14時29分十八秒PDT 2013 sjkdfjSent文件去在時間= 140734746993392 217545979656 – 2013-03-13 21:30:32

0

有一點需要注意:argc包含傳遞給您的程序的參數的計數+一個程序名稱。所以如果你用4個參數運行你的程序,argc = 5if (argc==4)將不會被滿足。如果這不能解決問題,那麼segfault的堆棧是什麼?

+0

謝謝布雷克, 我做gcc client.c -o客戶端 然後客戶端(主機名)f1。 TXT 6400 ,我得到一個seg故障 – 2013-03-13 21:09:10

+0

你可以在gdb中運行這個,並給出崩潰的堆棧跟蹤?如果你執行'$ gdb client'然後'運行(主機名)f1.txt 6400',它應該會崩潰,你可以運行'where'來獲得堆棧。我假設你的程序比你在這裏粘貼的更多,對吧? – Blake 2013-03-13 21:11:12

+0

我跑了它,但沒有崩潰:這是我回來的。你是正確的,但有更多的程序,但我不想讓任何人閱讀所有的哈哈。 (gdb)run geometry f1.txt 6400 啓動程序:geometry f1.txt 6400 未指定可執行文件。 使用「文件」或「exec-file」命令。 (gdb) 沒有堆棧。 – 2013-03-13 21:14:08