首页 > 解决方案 > 套接字:TCP 和 UDP 连接(C 语言)

问题描述

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

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

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

我知道 fd 表在父亲和孩子之间共享,但我不知道父亲进程中套接字发生的任何变化是否也会发生在孩子身上。

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

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

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

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

标签: csocketstcpudpfork

解决方案


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

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

由于您不能两次绑定套接字,因此可以使用以下内容来验证我的声明。(它是用 Perl 编写的,但 C 程序员应该能够毫无问题地阅读它。die抛出异常,$!is 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不。这个问题的前提是在由创建的套接字和被调用的套接字之间存在链接/连接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根据sendtowithNULL0for 最后两个参数定义。

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

send(sockfd, buf, len, flags);相当于sendto(sockfd, buf, len, flags, NULL, 0);

事实上,您必须将最后两个参数设置NULL0TCP 套接字。

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

如果sendto()在连接模式 ( SOCK_STREAM, SOCK_SEQPACKET) 套接字上使用,则忽略参数dest_addrand (如果不是and ,可能会返回错误)addrlenEISCONNNULL0


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

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

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

recv(sockfd, buf, len, flags);相当于recvfrom(sockfd, buf, len, flags, NULL, NULL);


推荐阅读