在新客户端连接到服务器后尝试 fork() [Socket Programming C]
Trying to fork() after new client connection to server [Socket Programming C]
所以我有一个服务器,它应该为与服务器的每个新连接创建一个新进程。因此,我将有多个客户端连接到一台服务器。
建立连接后,服务器应该return每个新客户端的随机数字 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 process\n");
}
else if (childpid == 0)
{ // child process
printf("\n child process\n");
printf("\n random num: %d\n", rand()); -----> Testing, should be unique for each client (its not!)
/* ***Server-Client Connected*** */
client_t client = generate_client();
}
printf("server: got connection from %s\n",
inet_ntoa(their_addr.sin_addr));
}
'rand'函数使用一个隐藏的'state'来生成下一个随机数。由于 parent 从不使用 rand,因此每个分叉 child 将获得相同的状态,并将生成相同的随机数序列。
一些可能的修复:
- 在 parent 中调用 rand(在分叉之前)。这将导致每个 child 以不同的状态开始。
- 在分叉前的 parent 中调用 rand,并保存 id 以供 child 使用。
- 使用 srand 为每个 child 设置随机数。
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
的文档,尤其是这一部分:
The srand() function uses the argument as a seed for a new sequence of pseudo-random numbers to be returned by subsequent calls to rand(). If srand() is then called with the same seed value, the sequence of pseudo-random numbers shall be repeated. If rand() is called before any calls to srand() are made, the same sequence shall be generated as when srand() is first called with a seed value of 1.
您要么打电话给 srand
,要么不打电话。如果不调用srand
,就和调用srand(1)
一样。所以这两种情况的逻辑是一样的。
如果两个进程生成不同的数字,则违反了 rand
的要求。正如文档所说,"If srand() is then called with the same seed value, the sequence of pseudo-random numbers shall be repeated." 你的两个进程调用 srand
具有相同的值(可能隐式为 1),因此它们 必须 都产生相同的序列。
我强烈建议您永远不要使用 rand
或 srand
。只需使用具有所需语义的函数。如果您需要在两个过程中都不同的随机数,请编写一个函数来生成它。另一种选择是在 fork
.
之后执行类似 srand(getpid() ^ (time(NULL)<<8))
的操作
所以我有一个服务器,它应该为与服务器的每个新连接创建一个新进程。因此,我将有多个客户端连接到一台服务器。
建立连接后,服务器应该return每个新客户端的随机数字 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 process\n");
}
else if (childpid == 0)
{ // child process
printf("\n child process\n");
printf("\n random num: %d\n", rand()); -----> Testing, should be unique for each client (its not!)
/* ***Server-Client Connected*** */
client_t client = generate_client();
}
printf("server: got connection from %s\n",
inet_ntoa(their_addr.sin_addr));
}
'rand'函数使用一个隐藏的'state'来生成下一个随机数。由于 parent 从不使用 rand,因此每个分叉 child 将获得相同的状态,并将生成相同的随机数序列。
一些可能的修复:
- 在 parent 中调用 rand(在分叉之前)。这将导致每个 child 以不同的状态开始。
- 在分叉前的 parent 中调用 rand,并保存 id 以供 child 使用。
- 使用 srand 为每个 child 设置随机数。
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
的文档,尤其是这一部分:
The srand() function uses the argument as a seed for a new sequence of pseudo-random numbers to be returned by subsequent calls to rand(). If srand() is then called with the same seed value, the sequence of pseudo-random numbers shall be repeated. If rand() is called before any calls to srand() are made, the same sequence shall be generated as when srand() is first called with a seed value of 1.
您要么打电话给 srand
,要么不打电话。如果不调用srand
,就和调用srand(1)
一样。所以这两种情况的逻辑是一样的。
如果两个进程生成不同的数字,则违反了 rand
的要求。正如文档所说,"If srand() is then called with the same seed value, the sequence of pseudo-random numbers shall be repeated." 你的两个进程调用 srand
具有相同的值(可能隐式为 1),因此它们 必须 都产生相同的序列。
我强烈建议您永远不要使用 rand
或 srand
。只需使用具有所需语义的函数。如果您需要在两个过程中都不同的随机数,请编写一个函数来生成它。另一种选择是在 fork
.
srand(getpid() ^ (time(NULL)<<8))
的操作