2012-01-30 69 views
0

我在寫一個自定義的VNC服務器客戶端。但是,每次執行159條命令後,服務器崩潰。我無法弄清楚它爲什麼崩潰,但它似乎是某種內存溢出的地方。套接字或std-i/o是否可能填滿?或者更可能是我的X控件的東西?C socket溢出內存

的源代碼:

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <sys/wait.h> 
#include <sys/select.h> 
#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <X11/extensions/XTest.h> 



void dostuff(int); 


void error(const char *msg) 
     { 
     perror(msg); 
     exit(1); 
     } 

int main(int argc, char *argv[]) 
     { 
     int sockfd, newsockfd, portno, pid; 
     socklen_t clilen; 
     struct sockaddr_in serv_addr, cli_addr; 

     if (argc < 2) 
       { 
       fprintf(stderr,"ERROR, no port provided\n"); 
       exit(1); 
       } 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    if (sockfd < 0) 
     error("ERROR opening socket"); 
    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    portno = atoi(argv[1]); 
    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = INADDR_ANY; 
    serv_addr.sin_port = htons(portno); 
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
       error("ERROR on binding"); 
    listen(sockfd,5); 
    clilen = sizeof(cli_addr); 


     while (1) 
       { 
       newsockfd = accept(sockfd, 
       (struct sockaddr *) &cli_addr, &clilen); 
       if (newsockfd < 0) 
       error("ERROR on accept"); 
       pid = fork(); 
       if (pid < 0) 
         error("ERROR on fork"); 
       if (pid == 0) 
         { 
         close(sockfd); 
         dostuff(newsockfd); 
         exit(0); 
         } 
       else close(newsockfd); 
       signal(SIGCHLD,SIG_IGN); 
       } 

     /* end of while */ 
     close(sockfd); 
     return 0; /* we never get here */ 
} 

/******** DOSTUFF() ********************* 
There is a separate instance of this function 
for each connection. It handles all communication 
once a connnection has been established. 
*****************************************/ 
void dostuff (int sock) 
{ 
while(1) 
     { 
     fflush(stdout); 

     int n; 
     char buffer[64]; 

     bzero(buffer,64); 
     printf("START:\n"); 
     n = read(sock,buffer,63); 
     printf("buffer[1]: %d \n", buffer[1]); 
     if (n < 0) error("ERROR reading from socket"); 


     Display *thedisplay; 
     Window thewindow; 
     int screen; 
     screen=buffer[0]-48; //first element is always the screen number 
     printf("screen = %d \n", screen); 

     thedisplay=XOpenDisplay(NULL); 
     thewindow=XRootWindow(thedisplay,screen); 
     int screenwidth = DisplayWidth(thedisplay, screen); 
     int screenheight = DisplayHeight(thedisplay, screen); 
     printf("width: %d, height %d \n", screenwidth, screenheight); 

     printf("buff[1] = %d \n", buffer[1]); 

     //switch on second char 
     switch(buffer[1]) 
     { 
     case 109: // second element == 'm' we treat it like a mousemove 

       printf("mousemovement\n"); 
       int xcoord = 100*(buffer[3]-48)+10*(buffer[4]-48)+1*(buffer[5]-48); 
       int ycoord = 100*(buffer[7]-48)+10*(buffer[8]-48)+1*(buffer[9]-48); 
       if (buffer[2]==49) xcoord = xcoord*(-1); 
       if (buffer[6]==49) ycoord = ycoord*(-1); 
       //printf("dx: %d, dy: %d \n", xcoord, ycoord); 
       Window windowreturned; 
       int xroot, yroot, xwin, ywin, mask_return; 
       XQueryPointer(thedisplay, thewindow, &windowreturned, &windowreturned, &xroot, &yroot, &xwin, &ywin, &mask_return); 
       //printf("xroot X: %d Y: %d \n", xroot, yroot); 
       //printf("xcoord+xroot %d %d \n", xcoord+xroot, ycoord+yroot); 
       //printf("screenwidth %d %d \n", screenwidth, screenheight); 
       if (xcoord+xroot > 0 && xcoord+xroot < screenwidth && ycoord+yroot>0 && ycoord+yroot<screenheight) 
        { 
        //printf("good to go\n"); 
        XWarpPointer(thedisplay,None,None,0,0,0,0,xcoord,ycoord); 
        XSync(thedisplay, False); 
        } 
       break; 
     case 107: //second element is a 'k' so we sendkey 
       SendKey (thedisplay, buffer[2]); 
       break; 
     case 98: // b us for mousebutton. 1 is leftclick, 2 is middle click, 3 is right click, 4 us up-scroll, 5 is downscroll 
       XTestGrabControl(thedisplay, True); 
//    XTestFakeButtonEvent(thedisplay, 1, True, 0); 
//    XTestFakeButtonEvent(thedisplay, 1, False, 0); 
       XTestFakeButtonEvent(thedisplay, buffer[2]-48, True, 0); 
       XTestFakeButtonEvent(thedisplay, buffer[2]-48, False, 0); 
       XSync (thedisplay, False); 
       XTestGrabControl (thedisplay, False); 
       break; 
     case 99: //second element is 'c', so we center on the screen 

       XWarpPointer(thedisplay,None,thewindow,0,0,0,0,screenwidth*.5,screenheight*.5); 
       XSync(thedisplay, False); 
       break; 

     default: 
       close(sock); 
       error("ERROR incorrect formattttttt\n"); 
       break; 
     } 

    printf("got this far\n"); 
    n = write(sock,"spanks\n",6); 
    if (n < 0) error("ERROR writing to socket\n"); 

} 
} 
+1

當你說服務器崩潰時,你究竟是什麼意思?任何錯誤消息?它掛了嗎?這個過程是否停止?你有堆棧轉儲嗎? – 2012-01-30 21:45:55

+1

如果read()只返回3個字節​​會怎麼樣?或者如果你發送2個命令,每個命令都是20個字節,你的read()調用讀取它們並返回40個字節?即看起來你沒有爲你的協議和代碼定義消息結構和消息幀。 – nos 2012-01-30 21:59:50

+0

它是客戶端上的SIGPIPE錯誤 – cyrusv 2012-01-30 22:25:03

回答

0

如何試圖在dostuff月底關閉套接字()? 服務器可能獲得太多打開的連接。

+0

dostuff()只被調用一次,並在while(1)循環中保持打開狀態,所以我很確定服務器只有一個打開的連接。 – cyrusv 2012-01-30 21:57:45

1

簡單地調用read並不能保證你將收到所有的63字節,或者你收到你希望的63字節..我建議你以某種方式確定你需要接收多少數據(發送數據首先是長度),然後將recv函數放在一個循環中,直到獲得所有數據爲止。還應該檢查發送函數(來自客戶端)。

+0

是的,我確定我可以訪問它。代碼工作正常,但只能進行約159次迭代。 – cyrusv 2012-01-30 22:09:04

+0

閱讀很有趣。不過,我相信我的讀取和寫入大小與客戶端和服務器代碼相匹配。如果它們不匹配,那麼會在多次迭代後導致崩潰? – cyrusv 2012-01-30 22:09:57

+0

'buffer [0] - 48'將ASCII碼變成二進制形式(即'9'=> 9')。 – dreamlax 2012-01-30 22:11:02

0

解決方案:錯誤在於XOpenDisplay在沒有關閉的情況下處於無限循環內。我只是在dostuff()中的無限循環之前移動XOpenDisplay命令。

這實際上不是套接字錯誤。