2015-05-11 22 views
3

我只是通过一些网站学习在Linux socket编程,这里是使用TCP的我在服务器端代码中的某些部分:分段错误(套接字编程(TCP)在C)

#define BufferLength 100 
#define SERVPORT 3111 
int main() 
{ 
    /* Variable and structure definitions. */ 
    int sd, 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; 

    /* Get a socket descriptor */ 
    if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    { 
    perror("Server-socket() error"); 
    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); 

    /* continue */ 
} 

当我做了最后一行(printf(“使用......”)),我遇到了分段错误,为什么?谢谢。

+1

你的代码看起来不错,它适用于我。在valgrind下运行它不会显示任何与内存相关的问题,这些问题可以解释段错误。我确实添加了所有必需的标题;我想你的问题可能是由于你错过了其中的一个或多个。你的编译器是否发出任何警告? –

+0

约翰,我编译这个程序时没有警告。另外,当我运行类似的代码时,我没有任何分割错误。 – user

+0

@user,我试着在我的Linux上编译你的一段代码,它运行时没有任何分段错误。你确定分段错误发生在printf吗? printf之后的代码是什么? –

回答

3

的代码所示偏出#include任何标题,因为它的立场将不编译由于一些未定义的符号。

但是,如果您遗漏了只编译代码所引用的任何库函数的原型,则会导致任何函数被假定为返回int

后一个事实可能是致命的或不是。

在64位系统中的至少是在用作参数来printf()inet_ntoa()的情况下是致命的,因为在64位的系统上它最有可能预期返回一个64位(char终场)值(但32位int )。因此(假设原型未命中)生成代码时,编译器假定inet_ntoa()返回32位int,这将导致“切断”返回地址的最高有效32位。试图从printf()这样的“残缺”,因此(最有可能)无效的地址引发未定义的行为,并在你的情况导致观察到分割违规。

通过添加解决这个问题,添加相关的原型(为inet_ntoa()):

#include <arpa/inet.h> 

编译器应该警告你这一点。要启用gcc的所有编译器警告,请使用选项-Wall -Wextra -pedantic。认真对待这些警告。

+0

您的解决方案通过包括标题为我工作,非常感谢! – user

0

inet_ntoa()似乎很可能返回NULL,导致在printf()中取消引用时发生段错误。我找不到明确指出Linux版本的inet_ntoa可以实现的直接参考,但是我发现了几个提出这种说法的人,而且这是代码中指针被解除引用的唯一一点。

该问题底部的答案:segmentation fault for inet_ntoa声明inet_ntoa可以返回NULL。但是,根据他的参考链接,我找不到这个事实的实际陈述。

有,做状态明白地INET_NTOA()可以空在这里返回一个MSDN文章(这是暗示性的,但当然,这并不直接适用于Linux的代码):https://msdn.microsoft.com/en-us/library/windows/desktop/ms738564%28v=vs.85%29.aspx

+1

很难相信它会返回NULL INADDR_ANY。很难相信,首先存在一个32位参数值可能出现的错误。 – EJP

+0

有点赞同你的第一点,但没有很多其他候选人在那里的段错误,这导致我作为唯一可能的候选人,即使不太可能。至于32位参数的错误,是不是有相当多的值不会转换为有效的32位IP地址? –