套接字:TCP和UDP连接(C语言)

Sockets: TCP and UDP connections (C language)

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

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

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

我知道 fd table 由 father 和 children 共享,但我不知道 father 进程中套接字发生的任何更改是否也会发生在 child仁.

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

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

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

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

1. If I bind that socket to a port and listen to that port, will also the socket, that was forked before those 2 calls, listen and be binded to that same port?

一旦有了文件描述符(由 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. If I use accept on the socket and the socket accepts a connection and links to the client socket: Will also the sockets that were forked be connected to that client socket?

没有。这个问题假设 accept 创建的套接字和调用 accept 的套接字之间存在 link/connection,但不存在任何这样的 link/connection(在任何的过程)。


3. Can I use a socket opened for TCP connections as a TCP reciever and UDP sender?

4. Can I use a socket opened for TCP connections as a UDP reciever and TCP sender?

没有。套接字可以是 TCP 套接字或 UDP 套接字。您不能通过 TCP 套接字 send/receive UDP 数据包,也不能通过 UDP 套接字 send/receive TCP 数据包。连试都试不出来

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


5. If I have a socket that was opened for TCP connections: Can I use sendto with the last 2 arguments NULL without any problems?

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

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

send(sockfd, buf, len, flags); is equivalent to sendto(sockfd, buf, len, flags, NULL, 0);

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

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

If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) socket, the arguments dest_addr and addrlen are ignored (and the error EISCONN may be returned when they are not NULL and 0)


6. Can I use on the client socket that was TCP connected the recvfrom with the last 2 arguments NULL?

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

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

recv(sockfd, buf, len, flags); is equivalent to recvfrom(sockfd, buf, len, flags, NULL, NULL);