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

时间:2019-06-18 15:29:51

标签: c

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

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);

1 个答案:

答案 0 :(得分:1)

您可以使用与发送服务器IP地址相同的方式将端口号发送给客户端。

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

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

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