Socket编程中的分段错误

Socket编程中的分段错误,c,linux,sockets,unix,segmentation-fault,C,Linux,Sockets,Unix,Segmentation Fault,我正在尝试在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 *

我正在尝试在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);
}

附言:我使用的是Ubuntu 12.04,在那里我实际编写了这些程序,并成功地执行了这些程序。但我最近迁移到Linux Mint 13肉桂。我重新编译了程序。也许他们也在造币厂成功地执行了死刑。但现在它似乎不知何故抓住了这个错误

我认为问题在于
inet\u ntoa()
缺少原型

这让编译器假设它返回
int

这使得下面这句话使应用程序崩溃:

printf("Server received connections from %s  \n", (char *)inet_ntoa(cli_addr.sin_addr));    
包含了
以下代码,即使使用
-Wall
也可以在没有警告的情况下编译这些代码

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

我认为问题在于
inet\u ntoa()
缺少原型

这让编译器假设它返回
int

这使得下面这句话使应用程序崩溃:

printf("Server received connections from %s  \n", (char *)inet_ntoa(cli_addr.sin_addr));    
包含了
以下代码,即使使用
-Wall
也可以在没有警告的情况下编译这些代码

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

如果您在64位系统上运行,您的呼叫

printf("Server received connections from %s  \n", 
    (char *)inet_ntoa(cli_addr.sin_addr));    
…可能会破裂。由于未包含
,因此您没有inet\u ntoa的定义。这将使编译器假定它返回一个
int
。由于
int
不一定是64位的(实际上大多数机器似乎不是),因此它的长度不足以存储返回的字符指针,因此printf会因无效字符串而崩溃。这发生在(例如)64位MacOS X上

只需将
#include
放在服务器的include中,就可以解决这个问题


您也不应忽略
int
socklen\u t
之间的差异,并解决
cli\u大小和
serv\u大小混用的问题,阅读已有的注释和答案以了解更多相关信息。

如果您在64位系统上运行,请拨打电话

printf("Server received connections from %s  \n", 
    (char *)inet_ntoa(cli_addr.sin_addr));    
…可能会破裂。由于未包含
,因此您没有inet\u ntoa的定义。这将使编译器假定它返回一个
int
。由于
int
不一定是64位的(实际上大多数机器似乎不是),因此它的长度不足以存储返回的字符指针,因此printf会因无效字符串而崩溃。这发生在(例如)64位MacOS X上

只需将
#include
放在服务器的include中,就可以解决这个问题


您也不应忽略
int
socklen\u t
之间的差异,并解决
cli\u大小和
serv\u大小的混淆问题,阅读已有的注释和答案以了解更多信息。

请尽量不要浪费其他人的时间。目前代码没有正确缩进,使阅读变得困难。根据我的经验,正确地缩进代码是一种很好的工程实践,而且这样做本身可能会暴露出您想要解决的问题。对于自己的帮助,请在read()和此类调用之后打印出errno value。有些像EAGAIN这样的值实际上不是错误。然后,正如下面已经有人暗示的那样,获取调试器并找出它崩溃的位置和原因。尝试使用getaddrinfo()的新方法,而不是手动填充serv_addr struct。另一个优点是getaddrinfo()支持IPv6。那么
serv.c
中的第47行是什么呢?
serv\u size
cli\u size
应该是
socklen\u t
类型。请参见
man bind
man accept
man connect
。请尽量不要浪费他人的时间。目前代码没有正确缩进,使阅读变得困难。根据我的经验,正确地缩进代码是一种很好的工程实践,而且这样做本身可能会暴露出您想要解决的问题。对于自己的帮助,请在read()和此类调用之后打印出errno value。有些像EAGAIN这样的值实际上不是错误。然后,正如下面已经有人暗示的那样,获取调试器并找出它崩溃的位置和原因。尝试使用getaddrinfo()的新方法,而不是手动填充serv_addr struct。另一个优点是getaddrinfo()支持IPv6。那么
serv.c
中的第47行是什么呢?
serv\u size
cli\u size
应该是
socklen\u t
类型。请参见
人工绑定
人工接受
,以及
人工连接
。非常感谢
#include
立即修复了警告和分段错误。socklen#t和int之间有什么区别?使用socklen_t的目的是什么?@IndradhanushGupta
socklen_t
始终为无符号且至少为32位。由于int是有符号的,在C中可能只有16位,所以引入了一个单独的数据类型来覆盖所有情况。非常感谢
#include
立即修复了警告和分段错误。socklen#t和int之间有什么区别?使用socklen_t的目的是什么?@IndradhanushGupta
socklen_t
始终为无符号且至少为32位。由于int是有符号的,在C中可能只有16位,因此引入了一种独立的数据类型来覆盖所有情况。