可以通过 telnet 访问我的服务器,但不能通过我的客户端访问

Can reach my server with telnet but not with my client

我目前正在用 C 编写一个用于学习网络的小型聊天应用程序。 我在 C 中使用带有套接字的传输控制协议进行开发。我能够使用不是我自己编码的客户端(在本地网络上)连接到我的服务器。现在 telnet 成功连接到我的聊天服务器(因此服务器和 telnet 客户端在同一台计算机上),我可以发送和接收消息,但我非常简单的客户端无法连接到它。 从一开始我就使用端口 9002,现在我正在尝试连接 IPv6 地址 ::1。 这是我服务器的 "accept client" 代码:

int main(void)
   {
    //Create the socket
    int sock = socket(AF_INET6, SOCK_STREAM, 0);

    printf("Socket créer\n");

    //Set up the socket interface
    struct sockaddr_in6 sin6 = { 0 };
    sin6.sin6_family = AF_INET6;
    sin6.sin6_port = htons(PORT);
    sin6.sin6_addr = in6addr_any; 

    //Bind the socket on the port
    if(bind(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr_in6)) == SO_ERROR)
    {
        perror("bind()");
        errx(EXIT_FAILURE, "Fail to bind");
    }

    //Make the sockey listen the port
    if(listen(sock, MAX_CLIENT) == SO_ERROR)
    {
        perror("listen()");
        errx(EXIT_FAILURE, "Fail to listen");
    }

    printf("Socket listening\n");

    int csock;
    size_t clientID = 0;
    --snip--

    while(1)
    {
        struct sockaddr_in6 csin6;
        memset(&csin6, 0, sizeof(struct sockaddr_in6));
        int sin6size = sizeof(struct sockaddr_in6);

        //Accept a communication
        printf("Wait for communication\n");
        csock = accept(sock, (struct sockaddr *) &csin6, &sin6size);
        printf("Connection accepted\n");
        char msg[16];
        sprintf(msg, "CONNECTED - %zu\n", clientID);
        send(csock, msg, sizeof(msg), 0);
        printf("Client %zu connected\n", clientID);

        //Handle client
       --snip--
    }

所以这是一个使用连接通信的套接字的基本连接。由于线程,服务器在 while 循环中处理多个客户端。
这里是客户端的代码:

void *sender(void *arg)
{
    int socket = (int)(long)arg;
    char buffer[BUFF_SIZE];
    while(1)
    {
        scanf("%s", buffer);
        send(socket, buffer, strlen(buffer), 0);
        bzero(buffer, BUFF_SIZE);
    }
}
int main(int argc, char *argv[])
{
    if(argc < 2)
        errx(EXIT_FAILURE, "Usage: ./client <server ip>\n");

    //Create the socket
    int sock = socket(AF_INET6, SOCK_STREAM, 0);
    struct hostent *hostinfo = NULL;
    hostinfo = gethostbyname2(argv[1], AF_INET6);
    if(hostinfo == NULL)
        errx(EXIT_FAILURE, "Can't connect to the server\n");

    //Set up the socket interface
    struct sockaddr_in6 sin6 = { 0 };
    sin6.sin6_family = AF_INET6;
    sin6.sin6_port = htons(PORT);
    sin6.sin6_addr = *(struct in6_addr *)hostinfo->h_addr; 

    if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
    {
        perror("connect()");
        errx(EXIT_FAILURE, "Fail to connect");
    }
    printf("Connection established\n");

    pthread_t sending;
    if(pthread_create(&sending, NULL, sender, (void *)(long)sock) != 0)
        printf("Fail to create a thread\n");

    //Handle reception
    char buffer[BUFF_SIZE];
    int n;
    while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
    {
        buffer[n] = '[=11=]';
        printf("%s", buffer);
    }

    printf("Erreur: %d\nConnection broken\n", n);
    pthread_cancel(sending);
    close(sock);
    return EXIT_SUCCESS;
}

所以我启动客户端:

~ ./client ::1

输出如下:

Connection established
Error: -1
Connection broken

虽然服务器还在"Waiting for communication"。这意味着服务器不接受连接,但客户端连接成功。

谢谢你的帮助。

可能已经是connect(),这里失败了:

if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)

SO_ERROR 不打算在这里使用,而是在异步连接失败时检索错误时用作套接字选项。 A(同步)connect() returns -1 出错并设置 errno,所以

if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == -1) {

...

后来这里的recv:

while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)

失败,错误号 ENOTCONN,因为连接事先失败。

相同的 SO_ERROR 错误出现在服务器代码的不同位置;有可能那里的 bind() 已经失败了!然后,对 listen() 的调用会将其自动绑定到一个空闲的临时端口,因此对 accept() 的调用以及对 accept() 的调用都会成功。

为什么调用 bind() 会失败?您可能必须在(重新)启动服务器时设置套接字选项 SO_REUSEADDR,否则如果连接仍处于 TIME_WAIT 状态,它可能会拒绝使用最近绑定的端口。将其直接放在 bind() 调用之前:

int one = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));

这可能会有所帮助。