使用 C (Ubuntu) 进行套接字编程中的分段错误

Posted

技术标签:

【中文标题】使用 C (Ubuntu) 进行套接字编程中的分段错误【英文标题】:Segmentation fault in socket programming with C (Ubuntu) 【发布时间】:2014-10-27 19:19:49 【问题描述】:

我正在编写一个 C 程序,它创建一个服务器端程序,该程序将消息“From Server”发送到客户端程序。但是,我对客户有问题。 strcpy(hostname,argv[1]); 线上的错误分段错误(核心转储)(我已在客户端代码上标记)。 以下是我的代码: 服务器:

/* Server program */    
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>


int main(int argc, char* argv[])

        /* Declaration of sock and newsock as integer variables to handle       the socket */
        int newsock,sock;

        /* Declaration of ptr to store info about the host */
        struct hostent* ptr;

        /* Declaration of address as sockaddr_in structure to store info    about Internet domain socket address */
        struct sockaddr_in address;

        /* Declaration of addrlen as integer to store the address length in         internet domain */
        int addrlen=sizeof(struct sockaddr_in);

        /* Declaration of buf as string to handle the message */
        char buf[100];

        /* Declaration of msg as string to store the message to be sent */
        char msg[50] ="From server";

        /* Declaration of portnum as integer to store port number */
        int portnum;

        /* Declaration of qsize as integer to store queue size */
        int qsize = 5;

        /* Store port number from the command line argument */
        portnum= atoi(argv[1]);

        /* Create a socket */
        printf("Creating socket");
        sock=socket(AF_INET,SOCK_STREAM,0);
        if(sock == -1)
        
            printf("\nCannot create a socket\n");
            return 0;
        

        /* Store the values in the address structure */
        address.sin_addr.s_addr=INADDR_ANY;
        address.sin_port=htons(portnum);
        address.sin_family=AF_INET;

        /* Binding to local address */
        printf("\nBinding to port\n");
        if(bind(sock,(struct sockaddr*)&address,sizeof(address))== -1)
        
            printf("\nCannot connect to host\n");
            return 0;
        

        /* Get local socket address */
        getsockname(sock,(struct sockaddr*)&address,(socklen_t*)&addrlen);
        printf("Opened socket:%d\nport:% d\n",sock, ntohs(address.sin_port));
        printf("Server\n sin_family = %d\n sin_addr.s_addr = %d\n sin_port = %d\n",address.sin_family, address.sin_addr.s_addr, ntohs(address.sin_port));

        /* Create a queue */
        printf("Queue size %d:",qsize);
        if(listen(sock,qsize) == -1)
        
            printf("\nCannot listen\n");
            return 0;
        

    for(;;)
        
            printf("\nWaiting for a connection\n");
            /* Get the connected socket and accept the connection */
            newsock=accept(sock,(struct sockaddr*)&address,(socklen_t*)&addrlen);
            printf("\nGot a connection");

            /* Send the message to the client */
            strcpy(buf,msg);
            printf("\nMessage sent to client:%s",buf);
            write(newsock,buf,strlen(buf)+1);

            /* Read read the message from the client */
            read(newsock,buf,100);
            printf("\nMessage received from client:%s",buf);

            /* Terminate the connection */
            if(close(newsock) == -1)
                
                printf("\nCould not close socket\n");
                return 0;
            
        

客户:

    /* Client program */

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

        int main(int argc, char* argv[])
        
            /* Declaration of sock as integer variable to handle the socket */
            int sock;

            /* Declaration of ptr to store info about the host*/    
            struct hostent* ptr;

            /* Declaration of address as sockaddr_in structure to store info    about Internet domain socket address */
            struct sockaddr_in address;

            /* Declaration of hostaddr as long to store the host address */
            long hostaddr;

            /* Declaration of buf and buf1 as string variables to handle the    message */  
            char buf[100],buf1[100];

            /* Declaration of amount as unsigned variable to store the number of        bytes returned by read system call      */
            unsigned amount;

            /* Declaration of hostname as string variable to store host name */
            char hostname[255];  

            /* Declaration of portnum as integer to store port number */
            int hostport;

            /* Get the host name and port number from the command line arguments        */
FAULT==================>   strcpy(hostname,argv[1]);
            hostport=atoi(argv[2]);

            /* Create a socket */
            printf("Making a socket");
            sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
            if(sock == -1)
            
                printf("\nCannot make a socket\n");
                return 0;
            

            /* Get IP address from host name */
            ptr=gethostbyname(hostname);

            /* Copy address into long */
            memcpy(&hostaddr,ptr->h_addr,ptr->h_length);

            /* Store the values in the address structure */
            address.sin_addr.s_addr=hostaddr;
            address.sin_port=htons(hostport);
            address.sin_family=AF_INET;

            /* Connect to the server */
            printf("\nConnecting to %s on port %d",hostname,hostport);
            if(connect(sock,(struct sockaddr*)&address,sizeof(address)) == -1)
            
                printf("\nCould not connect to host\n");
                return 0;
            

            /* Read the message from the server */
            amount=read(sock,buf,100);
            printf("\nMessage received from server:%s",buf);

            /* Write the message to the server */
            strcpy(buf1,"From client");
            write(sock,buf1,amount);
            printf("\nMessage sent to server:%s",buf1);

            /* Terminate the connection */
            printf("\nClosing socket\n");
            if(close(sock) == -1)
            
                printf("\nCould not close socket\n");
                return 0;
            
        

以下是使用 gdb 的调试会话:

pc03@pc03:~$ cc sockc.c
pc03@pc03:~$ ./a.out localhost.localdomain 58733
Segmentation fault
pc03@pc03:~$ cc -g sockc.c
pc03@pc03:~$ ./a.out localhost.localdomain 58733
Segmentation fault
pc03@pc03:~$ gdb ./a.out
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/pc03/a.out...done.
(gdb) run
Starting program: /home/pc03/a.out 

Program received signal SIGSEGV, Segmentation fault.
0x001a1210 in strcpy () from /lib/tls/i686/cmov/libc.so.6
(gdb) backtrace
#0  0x001a1210 in strcpy () from /lib/tls/i686/cmov/libc.so.6
#1  0x080486bf in main (argc=1, argv=0xbffff514) at sockc.c:38
(gdb) frame 1
#1  0x080486bf in main (argc=1, argv=0xbffff514) at sockc.c:38
38      strcpy(hostname,argv[1]);
(gdb) print hostname
$1 = "\277\022\000 \300\022\000\000\000\000\000\364\277\022\000\257\242\021\000\000\260\022\000\000\020\000\000\001\000\000\000\364\277\022\000\000\000\000\000X\363\377\277\177\246\021\000\260\312\022\000\230\375\377\267\001\000\000\000\001\000\000\000\000\000\000\000\240\362\377\277\364\277\022\000\000\000\000\000\000\000\000\000\060\363\377\277\200U\022\000\241\225\022\000|\212\022\000$\305\022\000\000\000\000\000\224\004\021\000\060\363\377\277\022\006\021\000P\363\377\277\324\002\021\000\002\000\000\000\064\003\021\000\a\000\000\000\220\246\023\000\020ii\rP\363\377\277\266\212\021\000\311\a\024\000\275\203\004\b\000\000\000\000$\203\004\bH\373\377\267\002\000\377\277 \346\021\000$\203\004\b\340\313\022\000\364\277\022\000\250\033\023\000\001\000\000\000\334\363\377\277f\220\021\000\200\364\377\277,1\021\000$\305\022\000\260\312\022", '\000' <repeats 21 times>"\260, \035\023\000܈\022"
(gdb) print argv
$2 = (char **) 0xbffff514

感谢您的帮助!

【问题讨论】:

我建议不要在用户输入中使用strcpy。你知道你的缓冲区有多大;请改用strncpy 之类的函数。 (gdb) run localhost.localdomain 58733 而不是run 请...当然它会在strcpy 上出现段错误,因为argv[1] 只是废话(你没有提供任何参数)。 尝试包含stdlib.h ;) PS:总是-Wall -Wextra编译 我还建议您检查argc 以查看在引用可能未初始化的argv[1] 之前是否传递了任何命令行参数。有了这样和上述的基本错误,可能会有其他人潜伏在那里。 write(sock,buf1,amount); 在客户端没有意义。您刚刚将固定字符串From client 放入buf1(12 个字节,包括终止NUL),但amount 包含刚刚从服务器读取的字节数。 【参考方案1】:

正如您最后的gdb 输出所示,问题出在以下语句: memcpy(&amp;hostaddr,ptr-&gt;h_addr,ptr-&gt;h_length);。很容易猜到ptr就是NULL

ptr=gethostbyname(hostname); 是问题的根源。如果hostname 未解析,ptr 将变为NULL,然后您将遇到分段错误。您应该始终检查函数的返回值。

【讨论】:

对不起,我还是没听懂。介意解释一下如何使用代码检查返回值吗?谢谢.. @radercraft 在man page of gethostbyname()中有你需要的所有解释

以上是关于使用 C (Ubuntu) 进行套接字编程中的分段错误的主要内容,如果未能解决你的问题,请参考以下文章

C语言linux套接字编程的5个基本函数

分段错误(核心转储)错误 C linux 套接字

recvfrom 中的分段错误(已创建核心转储)

FTP使用Socket编程

C中的服务器/套接字编程:数据未正确发送/接收?

使用C中的结构进行分段错误