您现在的位置是:首页 > 编程 > 

你说UDP是无连接的,那么UDP connect 有啥用?

2025-07-27 15:15:10
你说UDP是无连接的,那么UDP connect 有啥用? UDP 套接字调用 connect 函数和 TCP connect 调用引起 TCP 三次握手,建立 TCP 有效连接不同,UDP connect 函数的调用,并不会引起和服务器目标端的网络交互,也就是说,并不会触发所谓的“握手”报文发送和应答。 UDP 套接字进行 connect 操作主要是为了让应用程序能够接收“异步错误”的信息。事实

你说UDP是无连接的,那么UDP connect 有啥用?

UDP 套接字调用 connect 函数和 TCP connect 调用引起 TCP 三次握手,建立 TCP 有效连接不同,UDP connect 函数的调用,并不会引起和服务器目标端的网络交互,也就是说,并不会触发所谓的“握手”报文发送和应答。

UDP 套接字进行 connect 操作主要是为了让应用程序能够接收“异步错误”的信息。

事实上,当我们调用 sendto 或者 send 操作函数时,应用程序报文被发送,我们的应用程序返回,操作系统内核接管了该报文,之后操作系统开始尝试往对应的地址和端口发送,因为对应的地址和端口不可达,一个 ICMP 报文会返回给操作系统内核,该 ICMP 报文含有目的地址和端口等信息。

如果我们不进行 connect 操作,建立(UDP 套接字——目的地址 + 端口)之间的映射关系,操作系统内核就没有办法把 ICMP 不可达的信息和 UDP 套接字进行关联,也就没有办法将 ICMP 信息通知给应用程序。

如果我们进行了 connect 操作,帮助操作系统内核从容建立了(UDP 套接字——目的地址 + 端口)之间的映射关系,当收到一个 ICMP 不可达报文时,操作系统内核可以从映射表中出是哪个 UDP 套接字拥有该目的地址和端口,别忘了套接字在操作系统内部是全局唯一的,当我们在该套接字上再次调用 recvfrom 或 recv 方法时,就可以收到操作系统内核返回的“Connection Refused”的信息。

在对 UDP 进行 connect 之后,关于收发函数的使用,很多书籍是这样推荐的:

  • 使用 send 或 write 函数来发送,如果使用 sendto 需要把相关的 to 地址信息置零;
  • 使用 recv 或 read 函数来接收,如果使用 recvfrom 需要把对应的 from 地址信息置零。

其实不同的 UIX 实现对此表现出来的行为不尽相同。

一般来说,服务器端不会主动发起 connect 操作,因为一旦如此,服务器端就只能响应一个客户端了。不过,有时候也不排除这样的情形,一旦一个客户端和服务器端发送 UDP 报文之后,该服务器端就要服务于这个唯一的客户端。

一个类似的服务器端程序如下:

代码语言:javascript代码运行次数:0运行复制
#include "lib/common.h"

static int count;

static void recvfrom_int(int signo) {
    printf("\nreceived %d datagrams\n", count);
    exit(0);
}

int main(int argc, char **ar) {
    int socket_fd;
    socket_fd = socket(AF_IET, SOCK_DGRAM, 0);

    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_IET;
    server_addr.sin_addr.s_addr = htonl(IADDR_AY);
    server_addr.sin_port = ht(SERV_PORT);

    bind(socket_fd, (struct sockaddr *) &server_addr, sizeof(server_addr));

    socklen_t client_len;
    char message[MAXLIE];
    message[0] = 0;
    count = 0;

    signal(SIGIT, recvfrom_int);

    struct sockaddr_in client_addr;
    client_len = sizeof(client_addr);

    int n = recvfrom(socket_fd, message, MAXLIE, 0, (struct sockaddr *) &client_addr, &client_len);
    if (n < 0) {
        error(1, errno, "recvfrom failed");
    }
    message[n] = 0;
    printf("received %d bytes: %s\n", n, message);

    if (connect(socket_fd, (struct sockaddr *) &client_addr, client_len)) {
        error(1, errno, "connect failed");
    }

    while (strncmp(message, "goodbye", 7) != 0) {
        char send_line[MAXLIE];
        sprintf(send_line, "Hi, %s", message);

        size_t rt = send(socket_fd, send_line, strlen(send_line), 0);
        if (rt < 0) {
            error(1, errno, "send failed ");
        }
        printf("send bytes: %zu \n", rt);

        size_t rc = recv(socket_fd, message, MAXLIE, 0);
        if (rc < 0) {
            error(1, errno, "recv failed");
        }
        
        count++;
    }

    exit(0);
}

对这个程序做下解释:

  • 11-12 行创建 UDP 套接字;
  • 14-18 行创建 IPv4 地址,绑定到 AY 和对应端口;
  • 20 行绑定 UDP 套接字和 IPv4 地址;
  • 27 行为该程序注册一个信号处理函数,以响应 Ctrl+C 信号量操作;
  • 2-7 行调用 recvfrom 等待客户端报文到达,并将客户端信息保持到 client_addr 中;
  • 9-41 行调用 connect 操作,将 UDP 套接字和客户端 client_addr 进行绑定;
  • 4-59 行是程序的主体,对接收的信息进行重新处理,加上”Hi“前缀后发送给客户端,并持续不断地从客户端接收报文,该过程一直持续,直到客户端发送“goodbye”报文为止。

接下来我们实现一个 connect 的客户端程序:

代码语言:javascript代码运行次数:0运行复制
#include "lib/common.h"
# define    MAXLIE     4096

int main(int argc, char **ar) {
    if (argc != 2) {
        error(1, 0, "usage: udpclient <IPaddress>");
    }

    int socket_fd;
    socket_fd = socket(AF_IET, SOCK_DGRAM, 0);

    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_IET;
    server_addr.sin_port = ht(SERV_PORT);
    inet_pton(AF_IET, ar[1], &server_addr.sin_addr);

    socklen_t server_len = sizeof(server_addr);

    if (connect(socket_fd, (struct sockaddr *) &server_addr, server_len)) {
        error(1, errno, "connect failed");
    }

    char send_line[MAXLIE], recv_line[MAXLIE + 1];
    int n;

    while (fgets(send_line, MAXLIE, stdin) != ULL) {
        int i = strlen(send_line);
        if (send_line[i - 1] == '\n') {
            send_line[i - 1] = 0;
        }

        printf("now sending %s\n", send_line);
        size_t rt = send(socket_fd, send_line, strlen(send_line), 0);
        if (rt < 0) {
            error(1, errno, "send failed ");
        }
        printf("send bytes: %zu \n", rt);

        recv_line[0] = 0;
        n = recv(socket_fd, recv_line, MAXLIE, 0);
        if (n < 0)
            error(1, errno, "recv failed");
        recv_line[n] = 0;
        fputs(recv_line, stdout);
        fputs("\n", stdout);
    }

    exit(0);
}

对这个客户端程序做一下解读:

  • 9-10 行创建了一个 UDP 套接字;
  • 12-16 行创建了一个 IPv4 地址,绑定到指定端口和 IP;
  • 20-22 行调用 connect 将 UDP 套接字和 IPv4 地址进行了“绑定”;
  • 27-46 行是程序的主体,读取标准输入字符串后,调用 send 发送给对端;之后调用 recv 等待对端的响应,并把对端响应信息打印到标准输出。

一般来说,客户端通过 connect 绑定服务端的地址和端口,对 UDP 而言,可以有一定程度的性能提升。

因为如果不使用 connect 方式,每次发送报文都会需要这样的过程:

连接套接字→发送报文→断开套接字→连接套接字→发送报文→断开套接字 →………

而如果使用 connect 方式,就会变成下面这样:

连接套接字→发送报文→发送报文→……→最后断开套接字

我们知道,连接套接字是需要一定开销的,比如需要查路由表信息。所以,UDP 客户端程序通过 connect 可以获得一定的性能提升。

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/biancheng/1174182.html

相关标签:无
上传时间: 2025-07-21 13:45:58
留言与评论(共有 15 条评论)
本站网友 百度分享插件
18分钟前 发表
并不会触发所谓的“握手”报文发送和应答
本站网友 朱雯和朱静
15分钟前 发表
errno
本站网友 杜建华
8分钟前 发表
因为如果不使用 connect 方式
本站网友 标的额
20分钟前 发表
errno
本站网友 绿地老街坊
11分钟前 发表
关于收发函数的使用
本站网友 铁皮枫斗怎么吃
17分钟前 发表
所以
本站网友 利息税率
16分钟前 发表
该 ICMP 报文含有目的地址和端口等信息
本站网友 巫家坝
15分钟前 发表
操作系统内核可以从映射表中出是哪个 UDP 套接字拥有该目的地址和端口
本站网友 现代城
16分钟前 发表
%s\n"
本站网友 性欲异常
5分钟前 发表
%s\n"
本站网友 食品的分类
5分钟前 发表
该服务器端就要服务于这个唯一的客户端
本站网友 无锡金钱豹自助餐团购
15分钟前 发表
"send failed "); } printf("send bytes
本站网友 重庆小面50强
28分钟前 发表
&server_addr.sin_addr); socklen_t server_len = sizeof(server_addr); if (connect(socket_fd
本站网友 半岛晨报电子版
11分钟前 发表
%s\n"