Linux套接字:分段错误

时间:2013-08-25 15:41:14

标签: c++ c linux sockets

Linux n00b在这里。所以大约一个月前我安装了emacs和gcc / g ++编译器,并开始编程。我在线发现了一些echo服务器程序代码,将其复制并编译以测试网络功能。它已编译,但当我尝试运行它时,我收到错误消息:分段错误(核心转储)。当我仔细查看调试器详细信息时,它是“fwrite()”函数中的错误。我在编译和创建输出文件时将代码链接到库 libstdc ++。a ,因此它确实让我想知道实际库函数中是否存在一些严重错误,我需要返回,找到函数.c源代码,然后将它们添加到标题中以使其工作。代码发布在下面。还有其他人有这个问题吗?

#include <sys-socket.h>       /*  socket definitions        */
#include <sys-types.h>        /*  socket types              */
#include <netinet-in.h>        /*  inet (3) functions         */
#include <unistd.h>           /*  misc. UNIX functions      */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ether.h>
#include <string.h>


/*  Global constants  */

#define ECHO_PORT          2002
#define MAX_LINE           1000
#define LISTENQ            5


ssize_t Readline(int sockd, char *vptr,size_t maxlen) {
    ssize_t n, rc;
    char*    c;
    msghdr* buffer;

    buffer->msg_iov->iov_base = vptr;
    buffer->msg_iov->iov_len  = maxlen;

    for ( n = 1; n < maxlen; n++ ) {

      if ( (rc = recvmsg(sockd,buffer, 1)) == 1 ) {
    c = buffer->msg_iov->iov_base++;
        if (*c == '\n' )
        break;
    }
    else if ( rc == 0 ) {
        if ( n == 1 )
        return 0;
        else
        break;
    }
    else {
        if (rc < 0 )
        continue;
        return -1;
    }
    }

    buffer->msg_iov->iov_base = 0;
    return n;
}


/*  Write a line to a socket  */

ssize_t Writeline(int sockd, char *vptr) {
     msghdr     *buffer;


     buffer->msg_iov->iov_base = vptr;
     size_t      nleft = buffer->msg_iov->iov_len;
     ssize_t     nwritten;

    while ( nleft > 0 ) {
    if ( (nwritten = sendmsg(sockd, buffer, nleft)) < 0 ) {
          return -1;
    }
    nleft  -= nwritten;
    buffer += nwritten;
    }

    return nwritten;
}

int main(int argc, char *argv[]) {
    int       list_s;                /*  listening socket          */
    int       conn_s;                /*  connection socket         */
    short int port;                  /*  port number               */
    struct    sockaddr_in servaddr;  /*  socket address structure  */
    char     *endptr;                /*  for strtol()              */
    char      buffer[MAX_LINE];




    port = 5000;


    /*  Create the listening socket  */

    if ( (list_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
    fprintf(stderr, "ECHOSERV: Error creating listening socket.\n");
    exit(EXIT_FAILURE);
    }


    /*  Set all bytes in socket address structure to
        zero, and fill in the relevant data members   */

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(port);


    /*  Bind our socket addresss to the 
    listening socket, and call listen()  */

    if ( bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
    fprintf(stderr, "ECHOSERV: Error calling bind()\n");
    exit(EXIT_FAILURE);
    }

    if ( listen(list_s, LISTENQ) < 0 ) {
    fprintf(stderr, "ECHOSERV: Error calling listen()\n");
    exit(EXIT_FAILURE);
    }


    /*  Enter an infinite loop to respond
        to client requests and echo input  */

    while ( 1 ) {

    /*  Wait for a connection, then accept() it  */

    if ( (conn_s = accept(list_s, NULL, NULL) ) < 0 ) {
        fprintf(stderr, "ECHOSERV: Error calling accept()\n");
        exit(EXIT_FAILURE);
    }


    /*  Retrieve an input line from the connected socket
        then simply write it back to the same socket.     */

    Readline(conn_s, buffer, MAX_LINE-1);
    Writeline(conn_s, buffer);


    /*  Close the connected socket  */

    if ( shutdown(conn_s,0) < 0 ) {
        fprintf(stderr, "ECHOSERV: Error calling close()\n");
        exit(EXIT_FAILURE);
    }
    }
}

3 个答案:

答案 0 :(得分:4)

ssize_t Writeline(int sockd, char *vptr) {
     msghdr     *buffer;


     buffer->msg_iov->iov_base = vptr;

您的指针缓冲区未初始化。您可以查看此代码段以正确执行此操作:

      /* This structure contains parameter information for sendmsg.   */
   struct msghdr mh;

      /* The message header contains parameters for sendmsg.    */
   mh.msg_name = (caddr_t) &dest;
   mh.msg_namelen = sizeof(dest);
   mh.msg_iov = iov;
   mh.msg_iovlen = 3;
   mh.msg_accrights = NULL;            /* irrelevant to AF_INET */
   mh.msg_accrightslen = 0;            /* irrelevant to AF_INET */

   rc = sendmsg(s, &mh, 0);            /* no flags used         */
   if (rc == -1) {
      perror("sendmsg failed");
      return -1;
   }
   return 0;
}

sendmsg

答案 1 :(得分:1)

您没有在bufferWriteline()函数中设置ReadLine()指针变量。

ssize_t Writeline(int sockd, char *vptr) {
     msghdr     *buffer;

     //this is not appropriate as buffer does not point to appropriate memory.
     buffer->msg_iov->iov_base = vptr;

     size_t      nleft = buffer->msg_iov->iov_len;
     ssize_t     nwritten;
     ...    
    return nwritten;
}

如果不分配buffer->msg_iov->iov_basebuffer->msg_iov->iov_len甚至buffer,或者设置为适当的内存无效,则无法访问{。}}。

答案 2 :(得分:1)

你真的复制了这个,还是你复制了比特然后自己粘贴在一起?

至少要解决它不会自动崩溃的问题并不是很难 - 我没有进一步说明因为我的防火墙设置太严格而无法启动程序并使用随机端口,而且我不想破坏我的防火墙设置只是为了测试你的代码。

因此,正如所指出的那样msghdr *buffer;意味着buffer的指针未初始化。简单的解决方法是不使用指针,而是在需要时使用buffer的地址。然后,您需要具有iov数据结构。

所以,在接收中,你最终会得到这样的东西:

msghdr   buffer;
iovec    iov;

buffer.msg_iov = &iov;
...
if ( (rc = recvmsg(sockd, &buffer, 1)) == 1 ) {
    c = vptr++;
    buffer.msg_iov->iov_base = vptr;

注意缓冲区前面的&。我也更改了下一行,因为它在++指针上执行void,这在C ++中没有明确定义,因此编译器发出了警告。 (还有buffer未初始化的警告。

`WriteLine函数需要类似的处理。

iovec    iov;

buffer.msg_iov = &iov;
buffer.msg_iov->iov_base = vptr;
size_t      nleft = MAX_LINE;

... 
   if ( (nwritten = sendmsg(sockd, &buffer, nleft)) < 0 ) {
   ....

   nleft  -= nwritten;
   vptr += nwritten;
   buffer.msg_iov->iov_base = vptr;

同样,iov_base的增量正在增加一个void *,自从我在上面编写之后就没有定义,所以需要确保指针有不同的类型 - 重用{{ 1}}在这里很不错。

顺便说一下,我将vptr更改为设置为nleft,因为您没有传递该行的大小。我建议您更改它,以便它将大小作为参数,类似于MAX_LINE函数。

最后,请帮助自己一个忙,并在编译代码时使用ReadLine - 这意味着当你做“愚蠢”的事情时你会收到警告 - 它可能会起作用,但也可能无效。几乎所有来自编译器的警告都是有用的。

请记住,在C或C ++中使用指针时,应确保它指向某个东西。只写-Wall -Werror只给你一个指针,指针没有附加内存,所以在你使用那个指针之前,你应该以某种方式分配它。

我并不相信这涵盖了所有内容 - 但是它应该让你在某种程度上取得成功。