Linux网络编程之UDP

1. UDP 的 特点

  1. 无连接:内部不维护链接状态,也不需要三次握手。
  2. 基于消息的数据传输服务:不会有 粘包问题,数据包之间是有边界的
  3. 不可靠:数据包可能丢失,重复,乱序,缺少流量控制。
  4. 一般情况下比TCP更高效

2. UDP 客户/服务器模型
Linux网络编程之UDP_第1张图片
3. UDP 的 特点

  1. UDP 报文可能丢失,重复

  2. UDP报文可能乱序

  3. UDP缺乏流量控制

  4. UDP 协议报文可能被截断。如果发送的数据包大小超出接收缓存,多出的部分被丢弃

  5. recvfrom返回0,不代表链接关闭,因为UDP是无连接的

  6. ICMP 异步错误

  7. UDP connect
    7.1 UDP 调用connect不会有三次握手,只是将server端 IP & port 记录下来。
    7.2 UDP 可以多次调用connect,用于指定另外的 IP & port,或者断开当前IP & port 链接
    7.3 使用 connect 会更高效一些,当发送多个数据包时,省了每次都绑定port 建立链接的过程。
    7.4 采用 connect之后UDP 可以和TCP一样调用 send recv,read,write,当然也可以调用之前的 sendto, recvfrom。调用sendto的时候第五个参数必须是NULL,第六个参数是0.
    7.5 已连接的 UDP套接字发送异步错误会将错误返回到本进程。未连接的UDP套接字不接收任何异步错误。

  8. UDP外出接口确定
    如果 client端有多个IP。在进行UDP连接时会根据目的IP的相近性选择本地IP。
    port 口 是在 sendto()时确定的。

4. UDP 客户/服务器 简单事例
4.1 Server:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


int main()
{
    int listenfd = 0;
    if((listenfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        perror("socket error\n");
        exit(1);
    }
    printf("creat socket success\n");
    struct sockaddr_in seraddr;
    memset(&seraddr, 0, sizeof(seraddr));
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(51888);
    seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    if (bind(listenfd, (struct sockaddr *)&seraddr,sizeof(seraddr)) < 0)
    {
        perror("bind error\n");
        exit(1);
    }
    printf("bind success\n");
    char recbuf[40] = {0};
    struct sockaddr_in peer_addr;
    socklen_t addr_len;
    ssize_t ret;
    while (1)
    {
            memset(&peer_addr, 0, sizeof(peer_addr));
            addr_len = sizeof(peer_addr);
            ret = recvfrom(listenfd, recbuf, sizeof(recbuf), 0,
                             (struct sockaddr *)&peer_addr, &addr_len);
            if (ret == -1)
            {
                if (errno == EINTR)
                    continue;
                perror("receive error\n");
                exit(EXIT_FAILURE);
            }
            else if (ret > 0)
            {
                printf("the received data is %s\n", recbuf);
                sendto(listenfd, recbuf, sizeof(recbuf), 0,
                       (struct sockaddr *)&peer_addr, addr_len);
            }
            else if ()
    }
    close(listenfd);
   
    return 0;
}

Client:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
    int connfd = 0;
    if((connfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        perror("socket error\n");
        exit(1);
    }
    printf("creat socket success\n");
    struct sockaddr_in seraddr;
    memset(&seraddr, 0, sizeof(seraddr));
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(51888);
    seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    char recbuf[40] = {0};
    struct sockaddr_in peer_addr;
    socklen_t addr_len;
    ssize_t ret;
    char sendbuf[40] = {0};
    while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
    {
        sendto(connfd, sendbuf, sizeof(sendbuf), 0,
                       (struct sockaddr *)&seraddr, sizeof(seraddr));
        ret = recvfrom(connfd, recbuf, sizeof(recbuf), 0,NULL, NULL);
        printf("received data is %s\n", recbuf);
        memset(sendbuf, 0, sizeof(sendbuf));
        memset(recbuf, 0, sizeof(recbuf));
    }
    close(connfd);
   
    return 0;
}

你可能感兴趣的:(Linux网络编程)