2012-10-25 192 views
0

我試圖寫C.一個簡單的服務器 - 客戶端通信程序但作爲一個客戶端試圖連接到服務器,我不斷儘快獲得服務器端錯誤:分段錯誤

分割故障

服務器端代碼:

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

void error(char *); 

int main(int argc, char *argv[]) 
{ 
int sockfd, newsockfd, n, serv_size, cli_size, port_no, bindfd, readfd, writefd, listenfd; 
char sbuffer[256]; 
char *p; 
p = &sbuffer[0];  

struct sockaddr_in serv_addr, cli_addr; 

if (argc < 2) 
    error("No port no. Specified!\n"); 

//creating sever side socket  
sockfd = socket(AF_INET, SOCK_STREAM, 0); 
if (sockfd == -1) 
    error("Server side listening Socket could not be created!\n"); 


bzero((char *)&serv_addr, sizeof(serv_addr)); 
port_no = atoi(argv[1]); 
serv_addr.sin_family = AF_INET; 
serv_addr.sin_port = htons(port_no); 
serv_addr.sin_addr.s_addr = INADDR_ANY; 

//binding socket 
bindfd = bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); 
if (bindfd == -1) 
    error("Failed to bind server side socket!\n"); 

//listening for incoming connections 
listenfd = listen(sockfd, 5); 
if (listenfd == -1) 
    error("Failed to lisen to incoming connections!\n"); 

serv_size = sizeof(serv_addr); 
cli_size = sizeof(cli_addr); 
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &serv_size); 
if (newsockfd == -1) 
    error("Failed to accept connections from client!\n"); 

printf("Server received connections from %s \n", (char *)inet_ntoa(cli_addr.sin_addr));  
while(1) 
{ 
    bzero(p, sizeof(sbuffer)); 
    readfd = read(newsockfd, p, sizeof(sbuffer)); 
    if (readfd == -1) 
     error("Sorry. Unable to read message from client!\n"); 
    printf("Message Received: "); 
    puts(sbuffer); 

    bzero(p, sizeof(sbuffer)); 
    printf("\nEnter Your Message for client: "); 
    gets(sbuffer); 
    writefd = write(newsockfd, p, sizeof(sbuffer)); 
    if (writefd == -1) 
     error("Sorry. Message Could not be sent to client.\n"); 
    printf("Congratulations! Message has been sent to client.\n"); 
}  

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

客戶端代碼:

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

void error(char *); 
int main(int argc, char *argv[]) 
{ 
int sockfd, newsockfd, port_no, n, connectfd, readfd, writefd; 
char cbuffer[256]; 
char *ptr = &cbuffer[0]; 

struct sockaddr_in serv_addr; 
struct hostent *he; 

if (argc != 3) 
    error("Incomplete arguments!\n"); 

port_no = atoi(argv[2]); 
he = gethostbyname(argv[1]); 
if (he == NULL) 
    error("No Such Host!\n"); 

sockfd = socket(AF_INET, SOCK_STREAM, 0); 
if(sockfd == -1) 
    error("Sorry. Socket could not be created!\n"); 

bzero((char *)&serv_addr, sizeof(serv_addr)); 
serv_addr.sin_family = AF_INET; 
serv_addr.sin_port = htons(port_no); 
serv_addr.sin_addr = *((struct in_addr *)he->h_addr); 

connectfd = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); 
if (connectfd == -1) 
    error("Sorry. Could not connect to server.\n"); 

while(1) 
{ 
    bzero(ptr, sizeof(cbuffer)); 
    printf("\nEnter message for Server: \n"); 
    gets(cbuffer); 
    writefd = write(sockfd, ptr, sizeof(cbuffer)); 
    if (writefd == -1) 
     error("Sorry. Could not send message to Server."); 

    printf("Congratulations! Server Successfully Received your message.\n");  

    bzero(ptr, sizeof(cbuffer)); 
    readfd = read(sockfd, ptr, sizeof(cbuffer)); 
    if (readfd == -1) 
     error("Sorry. Message from server could not be read.\n"); 

    printf("Message Received: "); 
    puts(cbuffer); 
} 
return 0; 
} 
void error(char *msg) 
{ 
perror(msg); 
exit(1); 
} 

這是在編譯serv.c我的編譯時警告:

cc -o s serv.c 
serv.c: In function ‘main’: 
serv.c:47:52: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] 

附: :我使用的是Ubuntu 12.04,我實際上編寫了這些程序併成功執行了這些程序。但我最近遷移到Linux薄荷13肉桂。我重新編譯了這些程序。也許他們也成功地在造幣廠執行。但現在似乎已經以某種方式發現了這個bug。

+2

請儘量不要浪費別人的時間。目前代碼沒有正確縮進,使閱讀變得困難。同樣根據我的經驗,無論如何,正確縮進代碼都是很好的工程實踐,自己做這件事可能會暴露出您正在尋求解決的問題。 對於自己的幫助,在read()和這樣的調用之後,還打印出errno值。有像EAGAIN這些值其實不是錯誤。在此之後,作爲已經暗示的下面,請調試器,並找出它崩潰的原因以及爲什麼。 –

+1

http://www.cs.cmu.edu/~gilpin/tutorial/ – Jeyaram

+0

嘗試使用getaddrinfo()的新方法,而不是手動填充serv_addr結構體。另一個優點是getaddrinfo()支持IPv6。 – codewarrior

回答

4

如果您在64位系統上運行,您的呼叫;

printf("Server received connections from %s \n", 
    (char *)inet_ntoa(cli_addr.sin_addr));  

...可能會中斷。由於您沒有包含<arpa/inet.h>,因此您沒有inet_ntoa的定義。這將使編譯器假定它返回一個int。由於int不一定是64位(實際上似乎不是大多數機器),所以存儲返回的字符指針的時間不夠長,所以printf會導致無效字符串崩潰。發生這種情況(例如)64位的MacOS X.

只是簡單地把#include <arpa/inet.h>包括在服務器之間將解決這個問題。

你也應該不能忽視intsocklen_t之間的區別和修復混合起來cli_sizeserv_size的問題,閱讀已經存在的意見和答案,如果要了解他們。

+0

謝謝! '#include '立即修復了警告和分段錯誤。 –

+0

socklen_t和int有什麼區別? socklen_t的目的是什麼? –

+0

@IndradhanushGupta'socklen_t'總是無符號的,至少有32位。由於int是有符號的,並且在C中可能只有16位,因此'socklen_t'作爲單獨的數據類型引入以覆蓋所有情況。 –

0

我想說這個問題是inet_ntoa()缺失的原型。

這讓我們編譯器假定它返回int

這讓下面的行崩潰的應用程序:

printf("Server received connections from %s \n", (char *)inet_ntoa(cli_addr.sin_addr));  

已經包含<arpa/inet.h>的follwing代碼已經對子級不與-Wall甚至警告編譯。

printf("Server received connections from %s \n", inet_ntoa(cli_addr.sin_addr));