【问题标题】:How to execute a command only after the previous one has finished in a Server/Client program using sockets如何仅在使用套接字在服务器/客户端程序中完成前一个命令后执行命令
【发布时间】:2016-12-03 22:48:33
【问题描述】:

我正在使用套接字在 C 中制作客户端/服务器程序。服务器必须能够处理许多客户端。

服务器正确设置后,客户端连接到它,并发送“Ready”或“Kill”。服务器收到消息,回复“Go”或“Destroy”。

如果客户端收到的回复是“Go”,那么它执行一个传入参数的命令。该命令的执行方式如下:system(command)

如果客户端收到的回复是“Destroy”,则关闭客户端,销毁服务器。

服务器必须能够处理许多客户端,但它必须允许一次只允许一个客户端执行命令。另外,如果有客户端连接到服务器并发送“Kill”,那么队列中的所有客户端必须关闭,服务器必须立即销毁。

所以,为了实现这一点,我正在使用 select()

所以我遇到了这个规范的问题:它必须一次只允许一个客户端执行一个命令。

基本上,命令是在客户端执行的。而且我不希望两个客户端能够同时执行一个命令。

这是一个例子(这不是代码):

Client1 : system(echosleep hello1 goodbye1);

Client2 : system(echosleep hello2 goodbye2);

所以我的程序现在的工作方式,它会打印:

hello1
hello2
goodbye1
goodbye2

但我想要的是:

hello1
goodbye1
hello2
goodbye2

--> 而且我不明白服务器如何知道命令是否完成,因为它是在客户端执行的。

所以这是我的服务器代码结构(我没有在这里发布完整的代码,因为我的问题不是编写代码本身,而是更多关于结构,以及我应该将“Go”发送给客户端的确切位置。 .所以我省略了不相关的代码):

//initialize all client_socket[] to 0
//Create master_socket
//bind() master_socket
//listen() master_socket

//accept the incoming connection 
addrlen = sizeof(address);

while(TRUE) {
    //clear the socket set
    FD_ZERO(&readfds);

    //add master socket to set
    FD_SET(master_socket, &readfds);
    max_sd = master_socket;

    //add child sockets to set
    for ( i = 0 ; i < max_clients ; i++) {
        //socket descriptor
        sd = client_socket[i];

        //if valid socket descriptor then add to read list
        if(sd > 0) {
            FD_SET( sd , &readfds);
        }

        //highest file descriptor number, need it for the select function
        if(sd > max_sd) {
            max_sd = sd;
        }
    }

    //wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely
    activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);

    if (activity < 0) {
        printf("select()");
    }

    //If something happened on the master socket , then its an incoming connection
    if (FD_ISSET(master_socket, &readfds)) {
        if ((new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
            perror("accept()");
            return -1;
        }

        //Check message received from the Client
        //if message == Kill then destroy everything   (this is working)

        //if message == Ready, then send Go
        //When the Client receives Go, it will proceed with the execution of his command

        //add Client to the queue
        for (i = 0; i < max_clients; i++) {
            //if position is empty
            if( client_socket[i] == 0 ) {
                client_socket[i] = new_socket;              
                break;
            }
        }
    }
}

【问题讨论】:

    标签: c linux sockets select server


    【解决方案1】:

    我不明白服务器如何知道命令是否 完成与否

    简单的答案是,因为你提到的原因,它不能。除非客户端告诉它,否则服务器无法知道客户端内部发生了什么。

    因此,该问题的一种解决方案是让客户端在客户端完成执行命令后将另一条消息(例如“完成”)发送回服务器。收到“Done”消息后,服务器将知道客户端已完成执行,然后可以在另一个客户端上授权另一个命令。

    (顺便说一句,让客户端从网络接收字符串并将该字符串传递给 system() 是一个很大的潜在安全漏洞——“邪恶”服务器可能会传递像“rm -rf *”这样的字符串并导致您的客户端删除所有文件!因此在学术环境之外运行客户端软件时要小心)

    【讨论】:

    • 感谢您的回答!实际上,我只发送第一个字母(R 表示准备好等)。我在我的问题中写了完整的单词,因为我认为它会简化问题。但很高兴知道它实际上可能会导致安全问题。至于发送另一条消息,如“完成”,这是个好主意,但在我的任务中,我不允许添加任何其他消息。我希望有一个解决方案,比如使用 PID 或类似的东西。但看起来不可能。
    • 我想我没有提到的另一个细节是一次只有一个客户端应该处于活动状态。这就是为什么下一个客户端应该在前一个客户端完成后才开始。所以我不知道是否有办法知道客户是否仍然活跃。
    • (抱歉,忘记标记你)@Jeremy
    • 服务器可以检测客户端的 TCP 连接何时关闭(recv() 将返回 0 表示关闭的 TCP 连接),因此这是检测客户端是否不再处于活动状态的一种方法(至少对于“活跃”的一些定义)
    • 我认为这可行。但是我一次连接了超过 1 个客户端,所以当所有客户端都关闭时,recv() 会返回 0,还是在一个客户端关闭时返回 0? (经过一些测试,我认为它只会在所有客户端关闭时返回 0)@Jeremy
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-28
    相关资源
    最近更新 更多