【问题标题】:Sockets: TCP and UDP connections (C language)套接字:TCP 和 UDP 连接(C 语言)
【发布时间】:2020-04-29 15:47:34
【问题描述】:

我有一个进程必须建立一个接受 TCP 连接的服务器并创建一些子进程来完成这项工作。我创建了一个 TCP 套接字(不监听、绑定或接受)然后分叉。我有以下问题:

  1. 如果我将该套接字绑定到一个端口并监听该端口,那么在这两个调用之前分叉的套接字是否也会监听并绑定到同一个端口?

  2. 如果我在套接字上使用 accept 并且套接字接受连接并链接到客户端套接字:被分叉的套接字是否也会连接到该客户端套接字?

我知道fd表是父子共享的,但不知道父进程中socket发生的任何变化是否也会发生在子进程中。

  1. 我可以使用为 TCP 连接打开的套接字作为 TCP 接收方和 UDP 发送方吗?

  2. 我可以使用为 TCP 连接打开的套接字作为 UDP 接收方和 TCP 发送方吗?

  3. 如果我有一个为 TCP 连接打开的套接字:我可以使用带有最后 2 个参数 NULL 的 sendto 没有任何问题吗?我在在线手册中发现,对于基于连接的套接字,可以跳过最后两个参数,但我不知道我是否理解正确。如果可能的话,我希望孩子们能够在不知道他的地址的情况下向等待 recvfrom 的客户端发送数据报回复。

  4. 我可以在通过 TCP 连接的客户端套接字上使用最后 2 个参数为 NULL 的 recvfrom 吗?

【问题讨论】:

  • 我不知道我是否能够写出完整的答案(无论如何,以前的 cmets 一起提供了一个很好的答案),但我想澄清一件事:套接字不是分叉的!文件描述符(更好:整数本地进程变量)是分叉的。所以 1 和 2 的答案是肯定的......但不要期望每个分叉的进程都有独立的套接字克隆。

标签: c sockets tcp udp fork


【解决方案1】:

1.如果我将该套接字绑定到一个端口并监听该端口,那么在这两个调用之前分叉的套接字也会监听并绑定到同一个端口吗?

一旦您有了文件描述符(由socketaccept 创建),对该文件描述符的更改就会反映在所有进程中该描述符的克隆中。

由于您不能两次绑定套接字,因此可以使用以下内容来验证我的声明。 (它是用 Perl 编写的,但是 C 程序员应该可以毫无问题地读取它。die 抛出异常,$!strerror(errno)$!{EINVAL} 相当于 errno == EINVAL。)

#!/usr/bin/perl

use 5.014;
use warnings;

use Socket qw( pack_sockaddr_in AF_INET SOCK_STREAM INADDR_ANY SOMAXCONN );

socket(my $socket, AF_INET, SOCK_STREAM, 0)
   or die("socket: $!\n");

defined( my $pid = fork() )
   or die("fork: $!\n");

if (!$pid) {
   bind($socket, pack_sockaddr_in(0, INADDR_ANY))
      or die("bind: $!\n");
   listen($socket, SOMAXCONN)
      or die("listen: $!\n");
   exit;
}

waitpid($pid, 0) > 0
   or die("waitpid: $!\n");

if (bind($socket, pack_sockaddr_in(0, INADDR_ANY))) {
   say "Socket bound again. bind doesn't transcend processes.";
} else {
   if ($!{EINVAL}) {
      say "Socket already bound. bind transcends processes.";
   } else {
      die("bind in parent: $!\n");
   }
}

输出:

Socket already bound. bind transcends processes.

2.如果我在套接字上使用接受并且套接字接受连接并链接到客户端套接字:分叉的套接字也会连接到该客户端套接字吗?

没有。这个问题的前提是accept 创建的套接字和调用accept 的套接字之间存在链接/连接,但没有任何这样的链接/连接(在任何进程中)。


3.我可以使用为 TCP 连接打开的套接字作为 TCP 接收方和 UDP 发送方吗?

4.我可以使用为 TCP 连接打开的套接字作为 UDP 接收方和 TCP 发送方吗?

没有。套接字是 TCP 套接字或 UDP 套接字。您不能通过 TCP 套接字发送/接收 UDP 数据包,也不能通过 UDP 套接字发送/接收 TCP 数据包。甚至没有办法尝试。

但是,TCP 和 UDP 端口是独立的,因此您可以同时使用 TCP 端口 1234 和 UDP 端口 1234(使用两个不同的套接字)。


5.如果我有一个为 TCP 连接打开的套接字:我可以使用带有最后 2 个参数 NULL 的 sendto 没有任何问题吗?

是的。 send 可以在 TCP 套接字上调用,send 是根据 sendto 定义的,最后两个参数是 NULL0

根据我的(GNU/Linux)系统上的man 2 send

send(sockfd, buf, len, flags); 等价于sendto(sockfd, buf, len, flags, NULL, 0);

实际上,您必须使用 TCP 套接字将最后两个参数设置为 NULL0

根据我的 (GNU/Linux) 系统上的man 2 sendto

如果在连接模式(SOCK_STREAMSOCK_SEQPACKET)套接字上使用sendto(),则参数dest_addraddrlen 将被忽略(如果不使用EISCONN,则可能会返回错误NULL0)


6.我可以在 TCP 连接 recvfrom 的客户端套接字上使用最后 2 个参数为 NULL 吗?

是的。 recv 可以在 TCP 套接字上调用,recv 是根据 recvfrom 定义的,最后两个参数是 NULL

根据我的 (GNU/Linux) 系统上的man 2 recv

recv(sockfd, buf, len, flags); 等价于recvfrom(sockfd, buf, len, flags, NULL, NULL);

【讨论】:

    猜你喜欢
    • 2018-04-03
    • 2015-12-14
    • 2015-09-24
    • 2011-07-25
    • 1970-01-01
    • 2021-08-12
    • 2017-08-07
    • 1970-01-01
    • 2017-04-04
    相关资源
    最近更新 更多