Linux网络编程 - UDP发送/接受数据

UDP (User Datagram Protocol):用户数据报协议。

UDP 是一个不可靠的通信协议,没有重传和确认,没有有序控制,也没有拥塞控制。可以简单地理解为,在 IP 报文的基础上,UDP 增加的能力有限。

UDP编程

UDP中客户端和服务器端交互的图解:

image-20211102205255106

UDP Server :

  1. Create UDP socket.
  2. Bind the socket to server address.
  3. Wait until datagram packet arrives from client.
  4. Process the datagram packet and send a reply to client.
  5. Go back to Step 3.

UDP Client :

  1. Create UDP socket.
  2. Send message to server.
  3. Wait until response from server is received.
  4. Process reply and go back to step 2, if necessary.
  5. Close socket descriptor and exit.

主要是使用以下函数:

#include <sys/socket.h>
 
ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags, 
          struct sockaddr *from, socklen_t *addrlen); 
 
ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags,
                const struct sockaddr *to, socklen_t *addrlen);

recvfrom的参数含义:

  1. sockfd :本地创建的套接字描述符

  2. buff :指向本地缓存的指针

  3. nbytes :最大接收数据字节

  4. flags :与 I/O 相关的参数

  5. from 和 addrlen:返回对端发送方的地址和端口等信息

返回值:实际接收的字节数。

sendto的参数意义:

  1. sockfd :本地创建的套接字描述符

  2. buff :指向本地缓存的指针

  3. nbytes :最大接收数据字节

  4. flags :与 I/O 相关的参数

  5. to 和 addrlen,表示发送的对端地址和端口等信息。

UDP例子

UDP Server:

// Server side implementation of UDP client-server model

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
  
#define PORT    8080
#define MAXLINE 1024
  
// Driver code
int main() {
    int sockfd;
    char buffer[MAXLINE];
    char sendbuffer[MAXLINE];
    struct sockaddr_in servaddr, cliaddr;
      
    // Creating socket file descriptor
    if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }
      
    memset(&servaddr, 0, sizeof(servaddr));
    memset(&cliaddr, 0, sizeof(cliaddr));
      
    // Filling server information
    servaddr.sin_family    = AF_INET; // IPv4
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(PORT);
      
    // Bind the socket with the server address
    if ( bind(sockfd, (const struct sockaddr *)&servaddr, 
            sizeof(servaddr)) < 0 )
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
      
    int n;
    socklen_t len = (socklen_t)sizeof(cliaddr);  //len is value/resuslt
  


    for (;;) {
        n = recvfrom(sockfd, (char *)buffer, MAXLINE, 
                    MSG_WAITALL, ( struct sockaddr *) &cliaddr,
                    &len);
        buffer[n] = '\0';
        printf("Client : %s\n", buffer);
        
        sprintf(sendbuffer, "have recieve %d bytes", strlen(buffer));
        sendto(sockfd, (const char *)sendbuffer, strlen(sendbuffer), 0, 
                (const struct sockaddr *) &cliaddr, len);
        fprintf(stdout, "%s\n", sendbuffer);
    }

    return 0;
}

UDP Client:

// Client side implementation of UDP client-server model

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define PORT     8080
#define MAXLINE 1024
  
// Driver code
int main() {
    int sockfd;
    char buffer[MAXLINE];
    char *hello = "Hello from client";
    struct sockaddr_in     servaddr;
  
    // Creating socket file descriptor
    if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }
  
    memset(&servaddr, 0, sizeof(servaddr));
      
    // Filling server information
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    servaddr.sin_addr.s_addr = INADDR_ANY;
      
    socklen_t len = (socklen_t)sizeof(servaddr);  //len is value/resuslt
  
    // send msg
    while (fgets(buffer, MAXLINE, stdin) != NULL) {
        int i = strlen(buffer);
        if (buffer[i - 1] == '\n') {
            buffer[i - 1] = 0;
        }
        sendto(sockfd, (const char *)buffer, strlen(buffer), 0, 
                (const struct sockaddr *) &servaddr, len);
        fprintf(stdout, "message: %s have sent.\n", buffer);
        int n = recvfrom(sockfd, (char *)buffer, MAXLINE, MSG_WAITALL, 
                    (struct sockaddr *) &servaddr, &len);
        buffer[n] = '\0';
        printf("Server : %s\n", buffer);   
    }
  
    close(sockfd);
    return 0;
}

情况1: 只运行客户端、不开启服务端

可以看见,没有响应,也发送不了数据。程序会一直阻塞在 recvfrom 上。

image-20211102210825516

情况2: 先开启服务端,再开启客户端

image-20211102210628391

image-20211102210617910

也可以使用多个UDP客户端去和UDP服务器端通信,不再细述。

总结

  • UDP 是无连接的数据报程序,和 TCP 不同,不需要三次握手建立一条连接。
  • UDP 程序通过 recvfrom 和 sendto 函数直接收发数据报报文。

reference

[1] 极客时间 · 网络编程实战 :06 | 嗨,别忘了UDP这个小兄弟

[2] UDP Server-Client implementation in C

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux网络编程中的TCP和UDP是两种常见的传输协议。 TCP(Transmission Control Protocol)是一种基于连接的可靠传输协议。它提供了面向连接、可靠的数据传输服务。在TCP通信中,数据被分割成小的数据块,通过TCP连接按序传输,并且保证数据的可靠性,即使在网络拥塞或数据丢失的情况下也能重新传输丢失的数据。TCP适用于对可靠性要求较高的应用程序,如文件传输、电子邮件和网页浏览。 UDP(User Datagram Protocol)是一种无连接的不可靠传输协议。它提供了一种无序、不可靠的数据传输服务。在UDP通信中,数据数据包(也称为数据报)的形式发送,不进行连接建立和断开,也不保证数据的可靠性和按序传输。UDP适用于对实时性要求较高、对数据可靠性要求较低的应用程序,如音视频流媒体、在线游戏等。 在Linux中进行TCP和UDP网络编程可以使用Socket API。该API提供了一组函数和数据结构,用于创建套接字(socket)、绑定(bind)套接字到特定的IP地址和端口、监听(listen)连接请求、接受(accept)连接、建立连接(connect)、发送(send)和接收(receive)数据等操作。 你可以使用C语言或其他支持Socket API的编程语言来进行Linux网络编程,通过调用Socket API提供的函数来实现TCP或UDP通信。在编程过程中,你需要了解TCP和UDP的特点、使用套接字创建相应的连接类型、发送和接收数据的方式等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值