我得到的原因是:非套接字上的套接字操作

时间:2017-03-31 08:48:51

标签: c sockets

我正在编写c套接字,从客户端向服务器发送文件。在主客户端程序中调用client(),而在服务器程序中调用server()send_file()client()的辅助函数。我希望服务器在完成从当前客户端获取数据后等待另一个客户端连接 第一次迭代很好,但我在服务器的第二次迭代中从accept收到错误:server: accept: Socket operation on non-socket
是什么导致了这个问题?

int send_file(int socket, char *path) {
    int len;
    char buf[BUF_SIZE];
    char size[BUF_SIZE];
    struct stat stbuf;

    int fd = open(path, O_RDONLY);
    fstat(fd, &stbuf);
    sprintf(size, "%d", (int)stbuf.st_size);

    write(socket, size, BUF_SIZE);
    while((len = read(fd, buf, BUF_SIZE)) > 0) {
        write(socket, buf, len);
    }

    close(fd);
    return 1;
}

int client(char *src_path, char *dest_path, char *host_ip, int port) {

    int sock_fd;
    // Create the sock fd
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_fd < 0) {
        perror("client: socket");
        exit(1);
    }

    // Set the IP and port of the server to connect to.
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    if (inet_pton(AF_INET, host_ip, &server.sin_addr) < 1) {
        perror("client: inet_pton");
        close(sock_fd);
        exit(1);
    }

    // Connect to the server
    if (connect(sock_fd, (struct sockaddr *)&server, sizeof(server)) == -1) {
        perror("client: connect");
        close(sock_fd);
        exit(1);
    }

    send_file(sock_fd, src_path);

    return 0;
}

int server(int port) {
    printf("PORT: %d\n", port);

    char buf[BUF_SIZE];
    int sock_fd, client_fd;
    int len;

    // Create the socket FD.
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_fd < 0) {
        perror("server: socket");
        exit(1);
    }

    // Set information about the port (and IP) we want to be connected to.
    struct sockaddr_in server, client;
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr.s_addr = INADDR_ANY;
    memset(&server.sin_zero, 0, 8);

    // Bind the selected port to the socket
    if (bind(sock_fd, (struct sockaddr *)&server, sizeof(server)) < 0) {
        perror("server: bind");
        close(sock_fd);
        exit(1);
    }

    // Announce willingness to accept connections on this socket
    if (listen(sock_fd, MAX_BACKLOG) < 0) {
        perror("server: listen");
        close(sock_fd);
        exit(1);
    }

    while(1) {
        socklen_t client_size = sizeof(client);
        if ((client_fd = accept(sock_fd, (struct sockaddr *)&client, &client_size)) < 0) {
            perror("server: accept");
            close(sock_fd);
            exit(1);
        }

        read(client_fd, buf, BUF_SIZE);
        int size = atoi(buf);
        printf("Size: %d\n", size);

        while ((size > 0) && ((len = read(client_fd, buf, BUF_SIZE)) > 0)) {
            size -= len;
            buf[len] = '\0';
            printf("%s", buf);
        }

       close(client_fd);
    }

    close(sock_fd);

    exit(1);
}

1 个答案:

答案 0 :(得分:2)

服务器上的读取代码中存在缓冲区溢出。

    while ((size > 0) && ((len = read(client_fd, buf, BUF_SIZE)) > 0)) {
        size -= len;
        buf[len] = '\0';
        //  ^^^ Boom!!!
        printf("%s", buf);
    }

如果从套接字读取BUF_SIZE个字节,lenBUF_SIZE,则将buf [BUF_SIZE]的字节设置为\0。这必须破坏在缓冲区之后直接声明的套接字文件描述符。

我应该补充一点,修复它的最佳方法可能是声明缓冲区的大小为BUF_SIZE + 1而不是读取BUF_SIZE - 1个字节,因为IO会更有效率(你在写{ {1}}块。)