C语言实现UDP通信

下面是C语言实现UDP通信的完整攻略。

1. 确定需要使用的库和头文件

首先需要引入的头文件有:

#include <stdio.h>      //标准输入输出库
#include <stdlib.h>     //标准库
#include <string.h>     //字符串处理库
#include <unistd.h>     //Unix标准函数库
#include <sys/types.h>  //Unix/Linux系统基本类型定义
#include <sys/socket.h> //套接字函数库
#include <netinet/in.h> //IP地址和端口号定义

2. 创建UDP套接字

在准备使用UDP套接字之前,需要先调用 socket() 方法创建一个套接字。该方法接受三个参数:

int socket(int domain, int type, int protocol);

其中:

  • domain:协议域(通常是 AF_INET,表示TCP/IP协议);
  • type:套接字类型(通常是 SOCK_DGRAM,表示UDP套接字);
  • protocol:协议类型,通常为 0,表示默认协议。

创建UDP套接字的代码示例如下:

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

3. 套接字绑定地址和端口号

在创建UDP套接字后,需要将其绑定到一个本地地址和端口号上,以便于其他进程能够发送数据到该端口。可使用 bind() 方法进行绑定,该方法接受两个参数:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

其中:

  • sockfd:创建好的套接字;
  • addr:要绑定的地址和端口号;
  • addrlen:地址和端口号的长度。

代码示例如下:

struct sockaddr_in addr;
addr.sin_family = AF_INET;              //协议域
addr.sin_port = htons(PORT);            //端口号
addr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址(在本机的任何一个IP上都能够接收到信息)

if(bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
    printf("Bind Error.\n");
    return 0;
}

4. 发送UDP数据

在UDP通信中,发送数据时使用 sendto()方法。该方法接受四个参数:

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

其中:

  • sockfd:创建好的套接字;
  • buf:发送的数据内容;
  • len:发送的数据长度;
  • flags:调用操作方式,通常为 0
  • dest_addr:目标地址和端口号;
  • addrlen:目标地址和端口号的长度。

代码示例如下:

char sendbuf[1024] = "hello, this is a message from client.";
int sendbytes = sendto(sockfd, sendbuf, strlen(sendbuf), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr));

5. 接收UDP数据

在UDP通信中,接收数据时使用 recvfrom() 方法。该方法接受五个参数:

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

其中:

  • sockfd:创建好的套接字;
  • buf:接收到的数据内容;
  • len:接收数据的最大长度;
  • flags:调用操作方式,通常为 0
  • src_addr:发送方的地址和端口号;
  • addrlen:发送方的地址和端口号的长度。

代码示例如下:

char recvbuf[1024] = "";
struct sockaddr_in fromaddr;
socklen_t fromlen = sizeof(fromaddr);
int recvbytes = recvfrom(sockfd, recvbuf, 1024, 0, (struct sockaddr *)&fromaddr, &fromlen);
printf("Received message: %s\n", recvbuf);

示例说明

以下是一个简单的UDP客户端和服务器示例,可以直接运行在Linux上:

服务器

服务器会监听一个指定的端口,等待客户端发送信息。每当接收到客户端发来的信息时,会将消息打印出来,并向客户端回复一条信息。

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

#define PORT 8888

int main(int argc, char *argv[]) {
    int sockfd;
    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        printf("Socket Error.\n");
        return 0;
    }

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;              //协议域
    addr.sin_port = htons(PORT);            //端口号
    addr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址(在本机的任何一个IP上都能够接收到信息)

    if(bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
        printf("Bind Error.\n");
        return 0;
    }
    printf("======Waiting for client's request======\n");

    char sendbuf[1024] = "";
    char recvbuf[1024] = "";
    struct sockaddr_in fromaddr;
    socklen_t fromlen = sizeof(fromaddr);
    while(1) {
        //receieve the message
        int recvbytes = recvfrom(sockfd, recvbuf, 1024, 0, (struct sockaddr *)&fromaddr, &fromlen);
        if(recvbytes == -1) {
            printf("Receive Error.\n");
            break;
        }
        recvbuf[recvbytes] = 0;

        char *client_ip = inet_ntoa(fromaddr.sin_addr);
        printf("[Received From %s:%u]> %s\n", client_ip, ntohs(fromaddr.sin_port), recvbuf);

        //send back to client
        sprintf(sendbuf, "Your message has been received.");
        int sendbytes = sendto(sockfd, sendbuf, strlen(sendbuf), 0, (struct sockaddr *)&fromaddr, fromlen);
        if(sendbytes == -1) {
            printf("Send Error.\n");
            break;
        }
    }

    close(sockfd);
    return 0;
}

客户端

客户端会向服务器发送一条信息,并等待服务器回复。当收到服务器的回复时,会将消息打印出来。

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

#define PORT 8888

struct sockaddr_in addr;

int main(int argc, char *argv[]) {
    int sockfd;
    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        printf("Socket Error.\n");
        return 0;
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    char sendbuf[1024] = "hello, this is a message from client.";
    char recvbuf[1024] = "";
    int sendbytes = sendto(sockfd, sendbuf, strlen(sendbuf), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr));
    if(sendbytes == -1) {
        printf("Send Error.\n");
        return 0;
    }

    int recvbytes = recvfrom(sockfd, recvbuf, 1024, 0, (struct sockaddr *)&addr, (socklen_t *)&sizeof(struct sockaddr));
    if(recvbytes == -1) {
        printf("Receive Error.\n");
        return 0;
    }
    recvbuf[recvbytes] = 0;

    printf("Receive: %s\n", recvbuf);

    close(sockfd);
    return 0;
}

这样,我们就成功地用C语言实现了UDP通信。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言实现UDP通信 - Python技术站

(1)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C++迷宫问题的求解算法

    C++迷宫问题的求解算法 解决迷宫问题的算法种类很多,其中最常见的算法是回溯法和广度优先搜索。这里分别介绍这两种算法的实现以及具体的问题求解方式。 回溯法 回溯法是一种遍历所有解空间的算法,当我们在一条路径上探索到某条路程时,发现这条路无法到达正确的终点,我们就返回到上一个路口重新探索其他路径。这里我们以递归方式实现回溯法,其中每个节点的四个方向按照顺序依次…

    C 2023年5月22日
    00
  • 10种检测Python程序运行时间、CPU和内存占用的方法

    10种检测Python程序运行时间、CPU和内存占用的方法 在Python开发中,我们常常需要检测程序的运行时间、CPU和内存占用情况。这些信息对于代码优化和调试都非常有帮助。本篇文章就为大家介绍10种检测Python程序运行时间、CPU和内存占用的方法。 方法一:使用timeit 在Python中,timeit模块可以帮助我们计算代码片段的运行时间。其基本…

    C 2023年5月22日
    00
  • Qt5 实现主窗口状态栏显示时间

    作为一个Qt5开发者,我们要实现主窗口状态栏显示时间,可以按照以下步骤进行: Step 1:创建状态栏 首先,我们需要在主窗口中创建状态栏,可以在构造函数中添加如下代码: QMainWindow::QMainWindow(QWidget *parent) : QMainWindow(parent) { statusBar()->showMessage(…

    C 2023年5月22日
    00
  • C 标准库 time.h

    time.h 是 C 标准库中的一个头文件,它提供了一系列函数来操作日期和时间。下面我们来详细讲解如何使用 time.h 标准库。 时间表示法 在 time.h 中,通常使用 time_t 类型来表示时间戳(timestamp),即表示从 1970 年 1 月 1 日 0 时 0 分 0 秒到某一个时间点所经过的秒数。时间戳可以用 time() 函数获取。 …

    C 2023年5月10日
    00
  • C++如何切割String对象的方法

    C++有多种方法可以切割String对象,下面介绍其中两种。 方法一:使用stringstream stringstream是一个可用于输入和输出的字符串流类。可以通过向其写入字符串,再从中读取字符串,实现将字符串按照指定分隔符进行切割的功能。 示例代码如下: #include <iostream> #include <string>…

    C 2023年5月22日
    00
  • c语言如何实现两数之和

    关于“c语言如何实现两数之和”的问题,以下是一份完整攻略: 1. 首先,定义两个整型变量,分别存储两个数 在C语言中,我们可以使用int类型定义一个整型变量。因此,我们可以通过以下代码定义两个整型变量: int a, b; 其中,a和b分别用来存储两个数。 2. 输入两个数的值 接下来,我们需要从用户那里获取这两个数的具体值。在C语言中,我们可以使用scan…

    C 2023年5月23日
    00
  • C语言实现矩阵运算案例详解

    C语言实现矩阵运算案例详解 简介 矩阵是线性代数中非常重要的概念,也是很多领域中经常用到的数学工具。在计算机科学中,矩阵也得到了广泛的应用。在这篇文章中,我们将介绍如何使用C语言实现矩阵的基本运算,包括相加、相乘、转置、求逆等操作。我们将使用标准C语言来实现这些操作,不需要任何额外的库。 矩阵的基本操作 矩阵的表示 在讨论矩阵的操作之前,我们需要先了解矩阵的…

    C 2023年5月23日
    00
  • C++ pair的用法实例详解

    C++ pair的用法实例详解 简介 std::pair 是C++标准库中的一个数据结构,用于表示一个键值对。其中,键和值的数据类型可以不同,因此 std::pair 可以同时包含两个不同类型的对象。本文将详细介绍 std::pair 的定义方式,方法和示例。 定义与初始化 std::pair 内部的两个元素可以通过 first 和 second 访问,因此…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部