所以我有一个服务器,它应该为每个与服务器的新连接创建一个新进程。因此,我将有多个客户端连接到一台服务器。
建立连接时,服务器应为每个新客户端返回一个随机数 ID。
问题:服务器正在为连接到服务器的所有客户端(终端(打印相同的随机数 ID。
应该发生什么:子进程应该为新的唯一客户端连接生成 (rand((( id。证明每个新客户端都已连接到服务器。我的叉子正确吗?
while (1)
{
pid_t childpid; /* variable to store child's process id */
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if ((childpid = fork()) == -1)
{ // fork failed.
close(new_fd);
continue;
}
else if (childpid > 0)
{ // parent process
printf("n parent processn");
}
else if (childpid == 0)
{ // child process
printf("n child processn");
printf("n random num: %dn", rand()); -----> Testing, should be unique for each client (its not!)
/* ***Server-Client Connected*** */
client_t client = generate_client();
}
printf("server: got connection from %sn",
inet_ntoa(their_addr.sin_addr));
}
"rand"函数使用隐藏的"状态"来生成下一个随机数。由于父级从不使用 rand,因此每个分叉的子项将获得相同的状态,并将生成相同的随机数序列。
几个可能的修复:
- 在父级中对 rand 进行一次调用(在分叉之前(。这将导致每个孩子从不同的状态开始。
- 在分叉之前调用父级中的 rand,并保存 id 供子级使用。
- 使用srand为每个孩子设置随机查看。
int child_id = rand() ;
if ((childpid = fork()) == -1)
{ // fork failed.
close(new_fd);
continue;
}
... Later in the child.
printf("random num: %d", child_id) ;
您应该阅读rand
的文档,尤其是这部分:
srand(( 函数使用该参数作为新伪随机数序列的种子,这些伪随机数序列将由后续调用 rand(( 返回。如果使用相同的种子值调用 srand((,则应重复伪随机数序列。如果在对 srand(( 进行任何调用之前调用 rand((,则应生成与首次调用 srand(( 时相同的序列,种子值为 1。
要么你打电话srand
要么不打电话。如果不打电话给srand
,就和叫srand(1)
一样。因此,两种情况下的逻辑是相同的。
如果两个进程生成的数字不同,则将违反rand
要求。正如文档所说,"如果使用相同的种子值调用 srand((,则应重复伪随机数序列。调用srand
的两个进程都具有相同的值(可能隐式为 1(,因此它们必须都生成相同的序列。
我强烈建议您永远不要使用rand
或srand
。只需使用具有所需语义的函数。如果您需要两个进程中不同的随机数,请编写一个函数来生成该随机数。另一种选择是做类似srand(getpid() ^ (time(NULL)<<8))
后fork
.