2013-07-29 115 views
0

我正在寫簡單的TCP服務器,並且發現了一些問題。也許你可以幫我一下。 所以,我先寫了一個echo服務器(用來測試與計算機客戶端的連接)。它工作正常,但現在我需要改變一下。服務器應該在每隔X秒/分鐘連接並向每個客戶端發送相同的字符[]時將char [100]發送到客戶端。Linux TCP服務器每隔X秒向少數客戶端發送RAW數據

我嘗試了許多更改,但應用程序只會崩潰。在這段代碼中評論了我的一些「錯誤」。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/time.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <errno.h> 
#include <unistd.h> 

/* BufferLength is 100 bytes */ 
#define BufferLength 100 
/* Server port */ 
#define SERVPORT 6000 



int main(){ 

/* Variable and structure definitions. */ 

int sd, wyslij, sd2, rc, length = sizeof(int); 
int totalcnt = 0, on = 1; 
char temp; 
char buffer[BufferLength]; 
struct sockaddr_in serveraddr; 
struct sockaddr_in their_addr; 

fd_set read_fd; 
struct timeval timeout; 
timeout.tv_sec = 15; 
timeout.tv_usec = 0; 

char datadata[100] = "This is a test string from server lol!!! "; 

/* Get a socket descriptor */ 
if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ 
    perror("Server-socket() error"); 
    /* exit */ 
    exit (-1); 
}else 
    printf("Server-socket() is OK\n"); 

/* Allow socket descriptor to be reusable */ 

if((rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) < 0){ 
    perror("Server-setsockopt() error"); 
    close(sd); 
    exit (-1); 
}else 
    printf("Server-setsockopt() is OK\n"); 


    /* bind to an address */ 
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in)); 
serveraddr.sin_family = AF_INET; 
serveraddr.sin_port = htons(SERVPORT); 
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 

printf("Using %s, listening at %d\n", inet_ntoa(serveraddr.sin_addr), SERVPORT); 


if((rc = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0){ 
    perror("Server-bind() error"); 
    /* Close the socket descriptor */ 
    close(sd); 
    /* and just exit */ 
    exit(-1); 
}else 
    printf("Server-bind() is OK\n"); 

/* queue up to 10 clients */ 

if((rc = listen(sd, 10)) < 0){ 
    perror("Server-listen() error"); 
    close(sd); 
    exit (-1); 
}else 
    printf("Server-Ready for client connection...\n"); 

/* accept() the incoming connection request. */ 
int sin_size = sizeof(struct sockaddr_in); 

if((sd2 = accept(sd, (struct sockaddr *)&their_addr, &sin_size)) < 0){ 
    perror("Server-accept() error"); 
    close(sd); 
    exit (-1); 
}else 
    printf("Server-accept() is OK\n"); 

/*client IP*/ 

printf("Server-new socket, sd2 is OK...\n"); 
printf("Got connection from the client: %s\n", inet_ntoa(their_addr.sin_addr)); 

/* Wait for up to 15 seconds on */ 
/* select() for data to be read. */ 

FD_ZERO(&read_fd); 
FD_SET(sd2, &read_fd); 
rc = select(sd2+1, &read_fd, NULL, NULL, &timeout); 


/* rc = write(sd2, datadata, sizeof(datadata)); */ 
if((rc == 1) && (FD_ISSET(sd2, &read_fd))){ 

/* rc = write(sd2, datadata, sizeof(datadata)); */ 

/* Read data from the client. */ 
totalcnt = 0; 

    while(totalcnt < BufferLength){ 
    /* read() from client */ 

     rc = read(sd2, &buffer[totalcnt], (BufferLength - totalcnt)); 

     if(rc < 0){ 
      perror("Server-read() error"); 
      close(sd); 
      close(sd2); 
      exit (-1); 
     }else if (rc == 0){ 
      printf("Client program has issued a close()\n"); 
      close(sd); 
      close(sd2); 
      exit(-1); 
     } 
     else{ 
      totalcnt += rc; 
      printf("Server-read() is OK\n"); 
     } 
    } 
}else if (rc < 0){ 
    perror("Server-select() error"); 
    close(sd); 
    close(sd2); 
    exit(-1); 
} 
/* rc == 0 */ 
else{ 
    printf("Server-select() timed out.\n"); 
    close(sd); 
    close(sd2); 
    exit(-1); 
} 


/* Shows the data */ 

printf("Received data from the client: %s\n", buffer); 

/* write() some bytes of string, */ 
/* back to the client. */ 

printf("Server-Echoing back to client...\n"); 
rc = write(sd2, datadata, sizeof(datadata)); 

if(rc != totalcnt){ 
    perror("Server-write() error"); 
    /* Get the error number. */ 
    rc = getsockopt(sd2, SOL_SOCKET, SO_ERROR, &temp, &length); 

    if(rc == 0){ 
     /* Print out the asynchronously */ 
     /* received error. */ 
     errno = temp; 
     perror("SO_ERROR was: "); 
    }else 
     printf("Server-write() is OK\n"); 
     close(sd); 
     close(sd2); 
     exit(-1); 
    } 

/* Close the connection to the client and */ 
/* close the server listening socket. */ 

close(sd2); 
close(sd); 
exit(0); 

return 0; 
} 

非常感謝各位好友!

+2

它在哪裏崩潰?你有沒有在gdb或其他調試器中運行它? – Joe

+2

首先,您應該學習如何使用調試器,例如[GNU調試器](http://www.gnu.org/software/gdb/)。如果使用調試信息('-g'標誌爲GCC/clang)編譯並在調試器中運行程序,那麼程序將在發生崩潰時停止。然後,您可以使用'bt'命令來顯示功能回溯,以瞭解您是如何在故障現場結束的。如果它不在你的某個函數中,可以使用'up'命令遍歷調用堆棧,直到你處於其中一個函數中。你可以使用'p variable'來打印變量的值。檢查例如'NULL'指針。 –

+0

當我取消註釋行rc = write(sd2,datadata,sizeof(datadata))時崩潰;它有兩個地方在上面的代碼中註釋 – bluemuz

回答

2

你可能想看看D.J.伯恩斯坦的tcpserver(見http://cr.yp.to/ucspi-tcp/tcpserver.html)。基本上,您可以簡單地在tcpserver下運行C程序,並且tcpserver將處理所有事情,只要設置套接字,列出您使用的任何端口上的傳入連接等等。當傳入連接到達您指定的端口時, tcpserver會生成一個程序實例,並將來自客戶端的傳入信息傳遞給程序的STDIN,並將程序的STDOUT中的傳出信息傳回給客戶端。這樣,你可以專注於你的程序的核心邏輯(並簡單地讀/寫標準輸出/標準輸入),並讓tcpserver處理所有的繁重的插座等。

+0

偉大的事情!我經過了幾次測試,真是太棒了。謝謝你的幫助,我真的很感激! – bluemuz

1

那麼,我跑你的程序對一個簡單的TCP客戶端代碼並沒有看到任何崩潰。所以,你可能應該添加gdb信息。而且,在程序中,我沒有看到程序定期醒來的位置(您有註釋)並將數據發送給客戶端。您還應該考慮將客戶端fd添加到讀取fd集的列表中,並且有一個共同的select()調用。如果select()在偵聽器上返回一個read事件,那麼這是一個新的連接,你應該調用accept。如果select()在子fd上返回一個讀事件,那麼你需要調用recv()/ read()來讀取一些數據。

相關問題