Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用分叉为每个子进程提供唯一的ID_C++_Multithreading_Sockets - Fatal编程技术网

C++ 使用分叉为每个子进程提供唯一的ID

C++ 使用分叉为每个子进程提供唯一的ID,c++,multithreading,sockets,C++,Multithreading,Sockets,为了学习TCP套接字编程,我制作了一个简单的服务器和客户端。客户端将发送文件块,服务器将读取并写入文件。客户端和服务器可以正常工作,无需任何多处理。我想让多个客户端可以同时连接。我想给每个连接的客户端一个唯一的id,称为“client_id”。这是一个介于1和n之间的数字 我尝试使用fork()生成子进程,在子进程中我接受连接,然后读入数据并将其保存到文件中。但是,client_id变量没有跨进程同步,因此有时会递增,有时则不会递增。我不完全明白发生了什么事。client_id的值不应该重复,但

为了学习TCP套接字编程,我制作了一个简单的服务器和客户端。客户端将发送文件块,服务器将读取并写入文件。客户端和服务器可以正常工作,无需任何多处理。我想让多个客户端可以同时连接。我想给每个连接的客户端一个唯一的id,称为“client_id”。这是一个介于1和n之间的数字

我尝试使用fork()生成子进程,在子进程中我接受连接,然后读入数据并将其保存到文件中。但是,client_id变量没有跨进程同步,因此有时会递增,有时则不会递增。我不完全明白发生了什么事。client_id的值不应该重复,但有时我会看到数字出现两次。我相信这是因为在分叉时,子进程会得到父进程拥有的所有内容的副本,但并行进程之间没有同步

这是我的无限循环,它坐在那里等待连接客户端。在子进程中,我在另一个无限循环中传输文件,该循环在recv接收到0字节时终止

int client_id = 0;
while(1){

        // accept a new connection
        struct sockaddr_in clientAddr;
        socklen_t clientAddrSize = sizeof(clientAddr);

        //socket file descriptor to use for the connection
        int clientSockfd = accept(sockfd, (struct sockaddr*)&clientAddr, &clientAddrSize);
        if (clientSockfd == -1) {
            perror("accept");
            return 4;
        }
        else{   //handle forking
            client_id++;
            std::cout<<"Client id: "<<client_id<<std::endl;

            pid_t pid = fork();
            if(pid == 0){ 
                //child process
                std::string client_idstr = std::to_string(client_id);

                char ipstr[INET_ADDRSTRLEN] = {'\0'};
                inet_ntop(clientAddr.sin_family, &clientAddr.sin_addr, ipstr, sizeof(ipstr));

                std::string connection_id = std::to_string(ntohs(clientAddr.sin_port));
                std::cout << "Accept a connection from: " << ipstr << ":" << client_idstr
                 << std::endl;

                // read/write data from/into the connection
                char buf[S_BUFSIZE] = {0};
                std::stringstream ss;

                //Create file stream
                std::ofstream file_to_save;

                FILE *pFile;

                std::string write_dir = filedir+"/" + client_idstr + ".file";

                std::string write_type = "wb";
                pFile = fopen(write_dir.c_str(), write_type.c_str());
                std::cout<<"write dir: "<<write_dir<<std::endl;


                while (1) {
                    memset(buf, '\0', sizeof(buf));

                    int rec_value = recv(clientSockfd, buf, S_BUFSIZE, 0);

                    if (rec_value == -1) {
                      perror("recv");
                      return 5;
                    }else if(rec_value == 0){
                        //end of transmission, exit the loop
                        break;
                    }


                    fwrite(buf, sizeof(char), rec_value, pFile);

                }
                fclose(pFile);
                close(clientSockfd);
            }
            else if(pid > 0){
                //parent process
                continue;
            }else{
                perror("failed to create multiple new threads");
                exit(-1);
            }
        }

    }
int client_id=0;
而(1){
//接受新连接
clientAddr中的结构sockaddr_;
socklen\u t clientaddress size=sizeof(clientAddr);
//用于连接的套接字文件描述符
int clientSockfd=accept(sockfd,(struct sockaddr*)&clientAddr,&clientaddsize);
if(clientSockfd==-1){
佩罗(“接受”);
返回4;
}
else{//句柄分叉
客户端id++;

std::cout我可能错了,但这种计数器方法让我记忆犹新。计数器是如何定义的,它是局部变量吗?它应该有线程范围的生存时间,所以要么是全局变量,要么是静态局部变量,然后fork会在复制内存页时将其值复制到生成的进程。局部变量存储为临时变量Y和C++中发生的事情是未定义的。 如果您需要共享变量,可以使用共享内存..mmap等等

第二,它是进程的一个副本,从调用fork()的点开始执行。这里有什么?无限循环结束。循环将重新启动。如果pid为0,则应退出它

在for()循环中,有一个基于斐波那契原理的过程示例:

  • 父级将计数器从0增加到1,并称为fork。现在我们有了打印1的子级
  • 子进程完成传输并返回到循环的开头。当它接收到连接时,它将计数器增加到2。当它成功接收到连接时,父进程将计数器增加到2。现在您有4个进程

  • 如果你按顺序做更多的测试,你会看到重复的数量增加。如果你观察到数据,你可以看到你的任务管理器中的那些过程,或者说是顶部,PS输出。

    这个代码> STD::CoutWulnDunn不使用STD:::String,STD::OFSUM等等,指示更多的C++程序。如果这是原因,但您应该在子进程中
    close(sockfd);
    。@infixed Good point。更改了措辞。@dbush没有修复它。@jonnyd42添加静态到它,那么应该足够了忘记退出是我的问题。非常感谢!