实现一个简单的 UDP 客户端/服务器

发布于:2025-05-13 ⋅ 阅读:(13) ⋅ 点赞:(0)

在这里插入图片描述

/* udp_server.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>

typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;

#define IP          "192.168.5.28"
#define PORT        55535
#define BUFFER_SIZE 1024

int main()
{
  int         sockfd;
  sockaddr_in server_addr, client_addr;
  socklen_t   client_addr_len = sizeof(client_addr);
  char        buffer[BUFFER_SIZE];
  int         recv_len, send_len;
  char        client_ip[INET_ADDRSTRLEN];
  int         client_port;

  // 创建 UDP 套接字
  if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  {
    perror("socket failed");
    exit(EXIT_FAILURE);
  }

  // 设置服务器地址结构
  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = inet_addr(IP);
  server_addr.sin_port = htons(PORT);

  // 将 IPv4 地址从文本格式转换为网络字节序的二进制格式
  if (inet_pton(AF_INET, IP, &server_addr.sin_addr) <= 0)
  {
    perror("inet_pton failed");
    close(sockfd);
    exit(EXIT_FAILURE);
  }

  // 绑定套接字到指定地址和端口
  if (bind(sockfd, (sockaddr *)&server_addr, sizeof(server_addr)) < 0)
  {
    perror("bind failed");
    close(sockfd);
    exit(EXIT_FAILURE);
  }

  printf("Server listening on port %d...\n", PORT);

  while (1)
  {
    // 接收客户端消息
    memset(buffer, 0, BUFFER_SIZE);
    recv_len = recvfrom(sockfd, buffer, BUFFER_SIZE - 1, 0, (sockaddr *)&client_addr, &client_addr_len);
    if (recv_len < 0)
    {
      perror("recvfrom failed");
      continue;
    }

    // 将 IPv4 地址从网络字节序的二进制格式转换为文本格式
    if (NULL == inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN))
    {
      perror("inet_ntop failed");
      continue;
    }
    client_port = ntohs(client_addr.sin_port);

    printf("Client(%s %d): %s\n", client_ip, client_port, buffer);

    // 准备响应消息
    const char *response = "Message received successfully";
    int         rlen = strlen(response);
    // 发送响应给客户端
    send_len = sendto(sockfd, response, rlen, 0, (sockaddr *)&client_addr, client_addr_len);
    if (send_len != rlen)
      perror("sendto failed");
  }

  // 关闭套接字(不会执行到这里,按 Ctrl+C 终止程序)
  close(sockfd);
  return 0;
}
/* client.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>

typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;

#define SERVER_IP    "192.168.5.28"
#define SERVICE_PORT 55535
#define BUFFER_SIZE  1024

int main()
{
  int         sockfd;
  sockaddr_in server_addr;
  socklen_t   server_addr_len = sizeof(server_addr);
  char        buffer[BUFFER_SIZE];
  int         len, send_len, recv_len;

  // 创建 UDP 套接字
  if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  {
    perror("socket failed");
    exit(EXIT_FAILURE);
  }

  // 设置服务器地址结构
  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(SERVICE_PORT);
  // 将 IPv4 地址从文本格式转换为网络字节序的二进制格式
  if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0)
  {
    perror("inet_pton failed");
    close(sockfd);
    exit(EXIT_FAILURE);
  }

  while (1)
  {
    // 获取用户输入
    printf("Enter message to send (or 'exit' to quit): ");
    fgets(buffer, BUFFER_SIZE, stdin);

    // 移除换行符
    len = strlen(buffer);
    if ((len > 0) && ('\n' == buffer[len - 1]))
      buffer[--len] = '\0';

    // 检查是否退出
    if (strcmp(buffer, "exit") == 0)
      break;

    // 发送消息到服务器
    send_len = sendto(sockfd, buffer, len, 0, (sockaddr *)&server_addr, sizeof(server_addr));
    if (send_len != len)
    {
      perror("sendto failed");
      continue;
    }

    printf("Message sent to server.\n");

    // 接收服务器响应
    recv_len = recvfrom(sockfd, buffer, BUFFER_SIZE - 1, 0, (sockaddr *)&server_addr, &server_addr_len);
    if (recv_len < 0)
    {
      perror("recvfrom failed");
      continue;
    }

    printf("Server: %s\n\n", buffer);
  }

  // 关闭套接字
  close(sockfd);
  return 0;
}