c - 套接字:TCP 和 UDP 连接(C 语言)
问题描述
我有一个进程必须建立一个接受 TCP 连接的服务器并创建一些子进程来完成这项工作。我创建了一个 TCP 套接字(不监听、绑定或接受)然后分叉。我有以下问题:
如果我将该套接字绑定到一个端口并监听该端口,那么在这两个调用之前分叉的套接字也会监听并绑定到同一个端口吗?
如果我在套接字上使用 accept 并且套接字接受连接并链接到客户端套接字:分叉的套接字是否也会连接到该客户端套接字?
我知道 fd 表在父亲和孩子之间共享,但我不知道父亲进程中套接字发生的任何变化是否也会发生在孩子身上。
我可以使用为 TCP 连接打开的套接字作为 TCP 接收方和 UDP 发送方吗?
我可以使用为 TCP 连接打开的套接字作为 UDP 接收方和 TCP 发送方吗?
如果我有一个为 TCP 连接打开的套接字:我可以使用带有最后 2 个参数 NULL 的 sendto 没有任何问题吗?我在在线手册中发现,对于基于连接的套接字,可以跳过最后两个参数,但我不知道我是否理解正确。如果这是可能的,我希望孩子们能够在不知道他的地址的情况下向等待 recvfrom 的客户端发送数据报回复。
我可以在 TCP 连接 recvfrom 的客户端套接字上使用最后 2 个参数为 NULL 吗?
解决方案
1.如果我将该套接字绑定到一个端口并监听该端口,那么在这两个调用之前分叉的套接字也会监听并绑定到同一个端口吗?
一旦有了文件描述符(由socket
or创建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
根据sendto
withNULL
和0
for 最后两个参数定义。
根据man 2 send
我的(GNU/Linux)系统:
send(sockfd, buf, len, flags);
相当于sendto(sockfd, buf, len, flags, NULL, 0);
事实上,您必须将最后两个参数设置NULL
为0
TCP 套接字。
根据man 2 sendto
我的(GNU/Linux)系统:
如果
sendto()
在连接模式 (SOCK_STREAM
,SOCK_SEQPACKET
) 套接字上使用,则忽略参数dest_addr
and (如果不是and ,可能会返回错误)addrlen
EISCONN
NULL
0
6. 我可以在客户端套接字上使用 TCP 连接的 recvfrom 和最后 2 个参数 NULL 吗?
是的。recv
可以在 TCP 套接字上调用,并根据最后两个参数的withrecv
定义。recvfrom
NULL
根据man 2 recv
我的(GNU/Linux)系统:
recv(sockfd, buf, len, flags);
相当于recvfrom(sockfd, buf, len, flags, NULL, NULL);
推荐阅读
- c# - DataGrid WPF 中的 TextColumn 样式为只读的 TextColumn 错误
- java - 如何通过 JButton 的操作将 TextField 值从一个 JFrame 获取到一个类
- javascript - 在 html 输入元素中只允许正值(包括十进制值)
- javascript - 阻止网站保存您查看过的特定页面
- java - 有什么比 BufferedReader 的 readLine() 方法更快的替代方法?
- symfony - 如何检查树枝中的多个 if 条件?
- sql - 需要帮助将 ID 列与另一个 ID 列链接以进行插入
- android - (AMD 使用 Windows 和 Android Studio)错误:x86 仿真当前需要硬件加速
- java - 编写一个程序,使用具有随机发生器值的一维数组来打印每个组合被一对骰子掷出的次数
- hibernate - Spring Boot 2、HSQL 和具有多个模式的单元测试。具有自动生成功能的未知模式