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

标签 c sockets tcp tcpserver

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

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] = '\0';
        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

当服务器仍处于“等待通信”状态时。这意味着服务器不接受连接,但客户端连接成功。

感谢您的帮助。

最佳答案

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

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

SO_ERROR 并不打算在此处使用,而是作为异步连接失败时检索错误时的套接字选项。 (同步)connect() 出错时返回 -1 并设置 errno,所以这样做

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

...

稍后,这里的recv:

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

失败并显示 errno ENOTCONN,因为连接事先失败。

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

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

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

这可能会有所帮助。

关于可以通过 telnet 访问我的服务器,但不能通过我的客户端访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54443442/

相关文章:

c - C 中的循环内循环和随机生成

c - 为什么这段代码会计算 linux 和 windows 文本文件中不同的行数?

从双指针复制到 int 数组。它是否正确?

qt - 文件更改句柄,QSocketNotifier 由于套接字无效而禁用

sockets - Boost 在 SSL 和 TLS 之间进行选择

python - 如何通过 Python 套接字播放 mp3 文件?

c - 如何使用c在链表节点中传递两个参数?

sockets - 使用/proc/<pid>,如何识别网络端口号的应用程序?

sockets - 调整大量 XMPP 用户的 TCP 设置

linux - 找出哪个用户在应用程序内部创建了本地传入 TCP 连接