c - 使用带有随机端口的套接字将客户端绑定(bind)到服务器

标签 c

我正在尝试在服务器和多个客户端之间创建一个聊天室。除了将套接字绑定(bind)到随机端口外,一切都在正常运行。我通过

创建一个随机端口
server_info.sin_port = htons(0);

我的问题在于客户端能否使用该端口,或者我如何将端口号发送给客户端?

如果我将端口替换为静态数字,例如“8888”,程序将成功运行。我只是在收集端口时遇到问题。

服务器代码

int main()
{
    signal(SIGINT, catch_ctrl_c_and_exit);

    // Create socket
    server_sockfd = socket(AF_INET , SOCK_STREAM , 0);
    if (server_sockfd == -1) {
        char error[255];
        sprintf(error,"Fail to create a socket.");
    write(1,error,strlen(error));
        exit(EXIT_FAILURE);
    }

    // Socket information
    struct sockaddr_in server_info, client_info;
    int s_addrlen = sizeof(server_info);
    int c_addrlen = sizeof(client_info);
    memset(&server_info, 0, s_addrlen);
    memset(&client_info, 0, c_addrlen);
    server_info.sin_family = PF_INET;
    server_info.sin_addr.s_addr = INADDR_ANY;
    //TEST
    server_info.sin_port = htons(0);

    // Bind and Listen
    bind(server_sockfd, (struct sockaddr *)&server_info, s_addrlen);
    listen(server_sockfd, 5);

    // Print Server IP
    char start[100];
    getsockname(server_sockfd, (struct sockaddr*) &server_info, (socklen_t*) &s_addrlen);
    sprintf(start,"Start Server on: %s:%d\n", inet_ntoa(server_info.sin_addr), ntohs(server_info.sin_port));
    write(1,start,strlen(start));
    // Initial linked list for clients
    root = newNode(server_sockfd, inet_ntoa(server_info.sin_addr));
    now = root;

    while (1) {
        client_sockfd = accept(server_sockfd, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);

        // Print Client IP
        getpeername(client_sockfd, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);
    char client[255];
        sprintf(client,"Client %s:%d come in.\n", inet_ntoa(client_info.sin_addr), ntohs(client_info.sin_port));
    write(1,client,strlen(client));

        // Append linked list for clients
        ClientList *c = newNode(client_sockfd, inet_ntoa(client_info.sin_addr));
        c->prev = now;
        now->link = c;
        now = c;

        pthread_t id;
        if (pthread_create(&id, NULL, (void *)client_handler, (void *)c) != 0) {
            perror("Create pthread error!\n");
            exit(EXIT_FAILURE);
        }
    }

    return 0;
}

客户端代码

int main()
{
    signal(SIGINT, catch_ctrl_c_and_exit);

    // Naming
    char nick[255];
    sprintf(nick,"Please enter your name: ");
    write(1,nick,strlen(nick));
    if (fgets(nickname, LENGTH_NAME, stdin) != NULL) {
        str_trim_lf(nickname, LENGTH_NAME);
    }
    if (strlen(nickname) < 2 || strlen(nickname) >= LENGTH_NAME-1) {

      char nameerr[100];
      sprintf(nameerr,"\nName must be more than one and less than thirty characters.\n");
      write(1,nameerr,strlen(nameerr));
        exit(EXIT_FAILURE);
    }

    // Create socket
    sockfd = socket(AF_INET , SOCK_STREAM , 0);
    if (sockfd == -1) {
      char err[100];
      sprintf(err,"Fail to create a socket.");
      write(1,err,strlen(err));
        exit(EXIT_FAILURE);
    }

    // Socket information
    struct sockaddr_in server_info, client_info;
    int s_addrlen = sizeof(server_info);
    int c_addrlen = sizeof(client_info);
    memset(&server_info, 0, s_addrlen);
    memset(&client_info, 0, c_addrlen);
    server_info.sin_family = PF_INET;
    server_info.sin_addr.s_addr = inet_addr("127.0.0.1");
    //TEST
     server_info.sin_port = htons(0);

    // Connect to Server
    int err = connect(sockfd, (struct sockaddr *)&server_info, s_addrlen);
    if (err == -1) {
      char err[100];
      sprintf(err,"Connection to Server error!\n");
      write(1,err,strlen(err));
        exit(EXIT_FAILURE);
    }

    // Names
    getsockname(sockfd, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);
    getpeername(sockfd, (struct sockaddr*) &server_info, (socklen_t*) &s_addrlen);
    char conn[100];
    char ipval[100];
    sprintf(conn,"Connect to Server: %s:%d\n", inet_ntoa(server_info.sin_addr), ntohs(server_info.sin_port));
    sprintf(ipval,"You are: %s:%d\n", inet_ntoa(client_info.sin_addr), ntohs(client_info.sin_port));
    write(1,conn,strlen(conn));
    write(1,ipval,strlen(ipval));

    send(sockfd, nickname, LENGTH_NAME, 0);

    pthread_t send_msg_thread;
    if (pthread_create(&send_msg_thread, NULL, (void *) send_msg_handler, NULL) != 0) {
      char err[100];
      sprintf (err,"Create pthread error!\n");
    write(1,err,strlen(err));
        exit(EXIT_FAILURE);
    }

    pthread_t recv_msg_thread;
    if (pthread_create(&recv_msg_thread, NULL, (void *) recv_msg_handler, NULL) != 0) {
      char err[100]; 
      sprintf(err,"Create pthread error!\n");
      write(1,err,strlen(err));
        exit(EXIT_FAILURE);
    }

    while (1) {
        if(flag) {
      char bye[20];
      sprintf(bye,"\nBye\n");
      write(1,bye,strlen(bye));
            break;
        }
    }

    close(sockfd);
    return 0;
}

发现错误

connect(sockfd, (struct sockaddr *)&server_info, s_addrlen);

最佳答案

您可以像发送服务器IP地址一样将端口号发送给客户端。

为了通过 TCP 连接,客户端需要知道服务器的 IP 地址和非零端口号。

如果客户端和服务器在同一台计算机上运行,​​通常使用文件、环境变量或剪贴板来传达 IP 地址和端口号。

在您的示例中,您可以将 printf 添加到 server.c 以打印 IP 地址和端口号(使用函数 getsockname 获取它们)。然后,您可以在 client.c 中添加代码,从 argv[1] 获取 IP 地址,从 argv[2] 获取端口号。完成上述代码更改后,首先启动服务器,将打印的IP地址和端口号复制到剪贴板,然后将其粘贴到客户端的命令行,然后按Enter键启动客户端,它将在其 argv 中获取这两个参数。

关于c - 使用带有随机端口的套接字将客户端绑定(bind)到服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56652525/

相关文章:

c - "Undefined symbol <function> first referenced in file <file>"链接错误

c - 错误: assignment to expression with array type in c

c - ncurses,直接控制台输入,如何在没有*.lib,*.dll,*.h文件的vs17中实现?

c - 斐波那契数列计算器的问题

c - C中将数组和数组指针传递给函数的区别

c++ - 使用 C/C++ 获取错误消息 MSB6006 错误代码 2

c - Windows 控制台应用程序上的平台游戏和改进输入

c - getchar() 工作异常

计算机猜我的号码 C 编程

c - 找到给定回文日期的最近回文日期