udp编程 bind,connect函数的使用

说明

  • udp是一个无连接的通讯协议,普通通信模型如下:
    服务器 ------------------------------------------- 客户端
    左边是服务器 ,右边是客户端
  • 在该模型中,只有服务器需要使用到bind函数,不需要使用connect函数。

bind和connect这两个函数在udp编程中该如何使用?

  • 实际上,以上基本模式是通用模型,在一些情况下性能不是最好,在特殊情况下可以采用bind,connect函数来提高程序性能。

bind函数使用

  • bind函数作用为套接字绑定本地地址和端口号。
  • 服务器调用bind函数的作用很明显,但是客户端呢?客户端如果没有使用bind函数绑定自身的地址/端口,发送数据时,操作系统隐含的处理是:为该套接字随机分配一个合适的udp端口,确定使用的本地地址(以太网还是无线网以及其它网络),将该套接字和本地地址信息绑定,手动绑定可以避免这些隐含操作,从而提高性能。

connect函数使用

  • connect函数作用:指明套接字的目的地址/端口。
  • UDP的connect函数不像TCP,不会触发三次握手,只是在内核中记录对端的参数。

客户端使用connect函数

  • 基本模式下客户端每次发送数据都需要给sendto函数传递参数目标地址/端口,可以使用connect函数来减小这部分开销。
  • 基本模式下客户端每次发送数据,内核都有可能要做路由查询,connect可以减小这部分开销。
  • 客户端调用connect函数先指明目的地址/端口,然后就可以使用send函数发送数据了,因为此时套接字已经记录了目的地址/端口。
  • 客户端调用connect函数后,就可以直接使用recv来获取服务器返回,但是这样只能一对一通信了。
int main(int argc, char *argv[])
{
    int sd;
    struct sockaddr_in svr_addr;
    int ret;
    socklen_t addrlen = sizeof(struct sockaddr_in);
    char buf[BUFSZ] = {};

    if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    //先调用connect()函数,为套接字指定目的地址/端口
    svr_addr.sin_family = AF_INET;
    svr_addr.sin_port = htons(PORT);
    svr_addr.sin_addr.s_addr = inet_addr("192.168.1.166");
    connect(sd, (struct sockaddr* )&svr_addr, addrlen);

    while (1)
    {   
        memset(buf, 0, BUFSZ);
        printf("ple input: ");
        fgets(buf, BUFSZ, stdin);
        //sendto(sd, buf, BUFSZ, 0, (struct sockaddr* )&svr_addr, addrlen);
        send(sd, buf, BUFSZ, 0);

        ret = recvfrom(sd, buf, BUFSZ, 0, (struct sockaddr* )&svr_addr, &addrlen);
        printf("client: IPAddr = %s, Port = %d, buf = %s\n", inet_ntoa(svr_addr.sin_addr), ntohs(svr_addr.sin_port), buf);  
    }

    close(sd);  
    return 0;
}

服务器使用connect函数

  • 服务器可以使用connect,将导致服务器只接受这特定一个主机的请求。
  • 例子:java udp网络编程中,创建udp socket时可以传入对端ip地址,这样就能只接收指定ip的数据包,实现了过滤。

注意

  • UDP可以多次调用connect函数,当需要给同一个目的地址发送多次数据时,显式调用connect效率更高,未调用connect的UDP套接字发送数据前的环境准备大约会消耗每个UDP传输三分之一的开销。
  1. 清除之前的记录,包括路由环境等
  2. 记录新的IP和端口,准备好新的路由环境
  • UDP显式调用connect函数也可以避免一些错误,例如:高并发服务中,假设client A 通过非connect的UDP与server B,C通信.B,C提供相同服务.为了负载均衡,我们让A与B,C交替通信.A与B通信IPa:PORTa <----> IPb:PORTb,
    A与C通信IPa:PORTa’ <---->IPc:PORTc;
    假设PORTa与PORTa’相同了(在大并发情况下会发生这种情况),那么就有可能出现A等待B的报文,却收到了C的报文.导致逻辑错误.
  • 解决方法内就是采用connect的UDP通信方式.在A中创建两个udp,然后分别connect到B,C.
  • 根据connect的原理可知
  1. 设置目标节点的参数是单方向的,客户端使用了connect,客户端即可使用send,直接向服务器发送数据,如果服务器没有使用connect,服务器不能使用send向客户端发送数据。
  2. connect后也可以使用sendto等函数,只是会清除已设置的参数,发送完后需要重新connect(需要确认)。
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值