用c++实现一个简单的udp echo服务器

Anbinx 2021-02-22 AM 7℃ 0条
/**
 * @file udp_server.cpp
 * @author anbinx
 * @brief a simple udp echo server
 * @date 2021-02-22
 * 
 * @copyright Copyright (c) 2021
 * 
 */


#include <iostream>
#include <cstring>

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


#define MESSAGE_LEN 100


int main(int argc, char *argv[])
{
    int ret = -1;
    int sock_fd;
    struct sockaddr_in serv_addr, client_addr;
    char recv_buf[MESSAGE_LEN] = {0,};

    // create socket
    sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock_fd == -1) 
    {
        std::cout << "Failed to create socket!" << std::endl;
        exit(EXIT_FAILURE);
    }

    // create address and bind socket
    memset(&serv_addr, 0, sizeof(struct sockaddr_in));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(19998);
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    ret = bind(sock_fd, (sockaddr *)&serv_addr, sizeof(struct sockaddr_in));
    if (ret == -1) 
    {
        std::cout << "Failed to bind socket!" << std::endl;
        exit(EXIT_FAILURE);
    }

    // start to receive and echo
    for(;;)
    {
        memset(recv_buf, 0, sizeof(recv_buf));

        memset(&client_addr, 0, sizeof(struct sockaddr_in));
        socklen_t addr_size = sizeof(struct sockaddr_in);
        
        ret = recvfrom(sock_fd, (void *)recv_buf, MESSAGE_LEN, 0,
                        (sockaddr *)&client_addr, &addr_size);
        if (ret <= 0)
        {
            continue;
        }
        recv_buf[ret] = '\0';
        std::cout << "recv: " << recv_buf << std::endl;
        
        ret = sendto(sock_fd, (void *)recv_buf, MESSAGE_LEN,
                    0, (sockaddr *)&client_addr, addr_size);
        if (ret <= 0)
        {
            continue;
        }
    }

    close(sock_fd);

    return 0;
}

注释:

  • 第 33行通过 socket() 函数创建了一个套接字,参数 AF_INET 表示使用 IPv4 地址,SOCK_DGRAM 表示使用数据报格式套接字,IPPROTO_UDP 表示使用 UDP 协议。在 Linux 中,socket 也是一种文件,有文件描述符,可以使用 write() / read() 函数进行 I/O 操作。
  • 第45行将套接字与本地回环地址的19998端口绑定,sockaddr_in结构体是ipv4的地址格式,而sockaddr结构体是通用地址格式,两者大小相同,但结构体内部的定义稍有不同,故在传参时要进行强制类型转换。
  • 第60行接受来自客户端的消息,使用recvfrom是为了获得客户端的地址,recvfrom在收到消息后,会把消息中所包含的地址信息放到client_addr中,后面我们需要用这个地址回传信息。

吐槽

  • 刚刚接触c/c++网络编程,不得不说涉及的这些库函数参数非常复杂多样,而且风格也并不统一,入手时非常痛苦。
  • Linux的man手册真是神器,大部分的接口函数都有详细的说明,不过全是英文读起来还是有些许吃力,而目前的汉化手册维护不频繁,而且有很多函数都缺失了,不能不说是一个遗憾
标签: Linux, c/c++

非特殊说明,本博所有文章均为博主原创。

评论呢


captcha
请输入验证码