始终显示bind()失败:地址已在M1 macOS 12.4上使用

问题描述 投票:0回答:1

我这几天开始学习socket编程,但是我陷入了这个小故障。我在代码中使用了

SO_REUSEADDR
,我使用的端口是
6666
,当我尝试运行我的代码时,编译器告诉我
bind() failed: Address already in use
。当我尝试
lsof -i:6666
但什么也没有。

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <libc.h>

// When port = 8888, bind() failed: Illegal byte sequence
const int DEFAULT_PORT = 6666;

int main() {
    int listen_fd, max_fd, new_fd;
    fd_set master_set, working_set;
    int end_server = 0;
    int close_conn;
    char buffer[100];

    listen_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
    // -1 is returned if an error occurs.
    if(listen_fd == -1) {
        perror("socket() failed");
        exit(-1);
    }

    // Make the address and port bound to listen socket reusable.
    const int on = 1;
    int rc = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
    if (rc < 0) {
        perror("setsockopt() failed");
        close(listen_fd);
        exit(-1);
    }

    // Set socket to be nonblocking. All the sockets for
    // the incoming connections will also be nonblocking since
    // they will inherit that state from the listening socket.
    rc = ioctl(listen_fd, FIONBIO, (char *)&on);
    if (rc < 0)
    {
        perror("ioctl() failed");
        close(listen_fd);
        exit(-1);
    }

    // struct sockaddr is a general structure valid for any protocol.
    // https://qr.ae/pv4WMc
    // https://stackoverflow.com/a/21099172/16317008
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    // AF_LOCAL is used for native communication and AF_INET is used for network communication
    addr.sin_family = AF_LOCAL;
    // Let the system automatically obtain the IP address of the machine
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(DEFAULT_PORT);

    rc = bind(listen_fd, (const struct sockaddr *)&addr, sizeof(addr));
    if(rc == -1) {
        perror("bind() failed");
        close(listen_fd);
        exit(-1);
    }

    rc = listen(listen_fd, 30);
    if(rc == -1) {
        perror("listen() failed");
        close(listen_fd);
        exit(-1);
    }

    // Initialize fd_set
    max_fd = listen_fd;
    FD_ZERO(&master_set);
    FD_SET(listen_fd, &master_set);

    // Initialize the timeval struct to 3 minutes.
    // If no activity after 3 minutes this program will end.
    struct timeval timeout;
    timeout.tv_sec  = 3 * 60;
    timeout.tv_usec = 0;

    int desc_ready;
    do {
        // Copy the master fd_set over to the working fd_set.
        memcpy(&working_set, &master_set, sizeof(master_set));

        // On return, select() replaces the given descriptor sets with subsets consisting of those
        // descriptors that are ready for the requested operation.
        printf("Waiting on select()...\n");
        rc = select(max_fd + 1, &working_set, NULL, NULL, &timeout);
        if(rc < 0) {
            perror("select() failed");
            break;
        }

        // Check to see if the 3 minutes time out expired.
        if (rc == 0) {
            printf("select() timed out.  End program.\n");
            break;
        }

        // One or more descriptors are readable.
        // Need to determine which ones they are.
        desc_ready = rc;
        for (int i = 0; i <= max_fd  &&  desc_ready > 0; ++i) {
            // Check to see if this descriptor is ready.
            // FD_ISSET(fd, &fdset) is non-zero if fd is a member of fdset, zero otherwise.
            if (FD_ISSET(i, &working_set)){
                desc_ready -= 1;
                // Check to see if this is the listening socket.
                if(i == listen_fd) {
                    printf("Listening socket is readable\n");
                    do {
                        // Accept each incoming connection. If accept fails with EWOULDBLOCK,
                        // then we have accepted all of them.  Any other failure on accept
                        // will cause us to end the server.
                        new_fd = accept(listen_fd, NULL, NULL);
                        if (new_fd < 0) {
                            if (errno != EWOULDBLOCK) {
                                perror("accept() failed");
                                end_server = 1;
                            }
                            break;
                        }

                        // Add the new incoming connection to the master read set.
                        printf("New incoming connection - %d\n", new_fd);
                        FD_SET(new_fd, &master_set);
                        if (new_fd > max_fd)
                            max_fd = new_fd;
                    } while (new_fd != -1);
                }
                /****************************************************/
                /* This is not the listening socket, therefore an   */
                /* existing connection must be readable             */
                /****************************************************/
                else {
                    printf("  Descriptor %d is readable\n", i);
                    close_conn = 0;
                    // Receive all incoming data on this socket
                    // before we loop back and call select again.
                    do {
                        // Receive data on this connection until the recv fails with EWOULDBLOCK.
                        // If any other failure occurs, we will close the connection.
                        rc = (int)recv(i, buffer, sizeof(buffer), 0);
                        if (rc < 0) {
                            if (errno != EWOULDBLOCK) {
                                perror("recv() failed");
                                close_conn = 1;
                            }
                            break;
                        }
                        // Check to see if the connection has been closed by the client.
                        if (rc == 0) {
                            printf("Connection closed\n");
                            close_conn = 1;
                            break;
                        }

                        // Data was received.
                        int len = rc;
                        printf("%d bytes received\n", len);
                        // Echo the data back to the client.
                        rc = (int)send(i, buffer, len, 0);
                        if (rc < 0) {
                            perror("send() failed");
                            close_conn = 1;
                            break;
                        }
                    } while (1);
                    /*************************************************/
                    /* If the close_conn flag was turned on, we need */
                    /* to clean up this active connection.  This     */
                    /* clean up process includes removing the        */
                    /* descriptor from the master set and            */
                    /* determining the new maximum descriptor value  */
                    /* based on the bits that are still turned on in */
                    /* the master set.                               */
                    /*************************************************/
                    if (close_conn) {
                        close(i);
                        FD_CLR(i, &master_set);
                        // Determining the new maximum descriptor value
                        // based on the bits that are still turned on in the master set.
                        if (i == max_fd) {
                            while (FD_ISSET(max_fd, &master_set) == 0)
                                max_fd -= 1;
                        }
                    }
                } // End of existing connection is readable.
            } // End of if (FD_ISSET(i, &working_set))
        } // End of loop through selectable descriptors.
    }while (end_server == 0);

    // Clean up all the sockets that are open.
    for (int i=0; i <= max_fd; ++i) {
        if (FD_ISSET(i, &master_set))
            close(i);
    }
    return 0;
}
c sockets posix-select
1个回答
4
投票

您正在创建和设置的套接字类型不匹配。

您正在创建一个本地套接字(PF_LOCAL),这是一种在本地文件系统中创建的套接字。从您的代码看来您想使用普通的互联网套接字。要使其正常工作,请将 PF_LOCAL 和 AF_LOCAL 更改为 AF_INET。

如果您的意图是使用本地套接字,那么“bind”需要“struct sockaddr_un”而不是“struct sockaddr_in”。在该结构中,您应填写文件名而不是端口。另外,要释放并重用此类套接字,您应删除相应的文件。

© www.soinside.com 2019 - 2024. All rights reserved.