UDP通信调试笔记

该文提供了两个C语言程序,分别用于UDP组播消息的发送和接收。发送端代码(udp_send.c)创建UDPsocket,读取用户输入的数据并使用htonl转换为网络字节序,然后通过sendto函数发送。接收端代码(udp_recv.c)创建socket,加入组播,绑定端口,接收并打印数据,使用ntohl将网络字节序转换回主机字节序。
摘要由CSDN通过智能技术生成

1.UDP发送端代码udp_send.c

//发送组播消息
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

typedef struct udpData {
    uint32_t type;
    uint32_t length;
    char srcIp[32];  
    uint32_t status;
} udpData_t;

int main(int arg, char * args[])
{
    //可执行文件传参
    //判断执行参数是否满足
    if(arg != 3)
    {
        printf("请传递组播ip,及要绑定的端口号\n");
        return -1;
    }

    //创建UDP socket
    int udp_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (udp_socket_fd == -1)
    {
        printf("create socket failed ! error message :%s\n", strerror(errno));
        return -1;
    }

    //地址信息
    struct sockaddr_in dest_addr = {0};
    dest_addr.sin_family = AF_INET;   
    int dest_port = 0;
    char dest_ip[32] = {0};
    udpData_t send_data;

    dest_port = atoi(args[2]);  //设置目的IP端口
    dest_addr.sin_port  = htons(dest_port);   //网络通信都使用大端格式
    dest_addr.sin_addr.s_addr =  inet_addr(args[1]);  //32位的整形  

    printf("test type:\n");
    scanf("%d",&send_data.type);
    send_data.type = htonl(20);

    printf("test length:\n");
    scanf("%d",&send_data.length);
    send_data.length = htonl(send_data.length);

    printf("test srcIp:\n");
    scanf("%s",send_data.srcIp);

    printf("test status:\n");
    scanf("%d",&send_data.status);
    send_data.status = htonl(send_data.status);

    if (sendto(udp_socket_fd, (void *)&send_data, sizeof(send_data), 0, (struct sockaddr *) &dest_addr, sizeof(dest_addr)) == -1)
    {
        printf("sendto failed ! error message :%s\n", strerror(errno));
        return -1;
    }   

    //关闭socket
    close(udp_socket_fd);
    bzero(&send_data, sizeof(send_data));

    return 0;
}

2.UDP接收端代码udp_recv.c

//组播消息接收
#include <stdio.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>

typedef struct udpData {
    uint32_t type;
    uint32_t length;
    char srcIp[32];   
    uint32_t status;
} udpData_t;

int main(int argc,char *argv[])
{
	//可执行文件传参
	//判断执行参数是否满足
	if(argc != 3)
	{
		printf("请传递组播ip,及要绑定的端口号\n");
		return -1;
	}

	//将接收到的端口号并转换为int型
	int port = atoi(argv[2]);
	if( port < 1025 || port > 65535 )//0-1024供系统使用,最大可到65535
	{
		printf("端口号范围应在1025~65535");
		return -1;
	}
	
	//创建udp socket  使用IPv4协议,UDP数据报,0:默认属性
	int udp_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
	if(udp_socket_fd < 0 )
	{
		perror("creat socket fail\n");
		return -1;
	}

		
	//加入组播,组播地址224.0.0.0~239.255.255.255 
	struct ip_mreq mul = {0};
	mul.imr_multiaddr.s_addr = inet_addr(argv[1]);  //设置组播地址
	mul.imr_interface.s_addr = inet_addr("0.0.0.0");  
	int ret = setsockopt(udp_socket_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mul, sizeof(mul));
	if(ret < 0)
	{
		perror("set sock opt fail\n");
		return -1;
	}
	else
	{
		printf("已经加入组:[%s:%d], 等待接收组消息。。。\n", argv[1], port);
	}
	
	//设置UDP的地址并绑定 
	struct sockaddr_in  addr = {0}; //地址信息存放
	addr.sin_family  = AF_INET;  //使用IPv4协议
	addr.sin_port	= htons(port);   //网络通信都使用大端格式
	addr.sin_addr.s_addr =  inet_addr("0.0.0.0");  //32位的整形

	ret = bind(udp_socket_fd, (struct sockaddr*)&addr, sizeof(addr));
	if(ret < 0)
	{
		perror("bind fail:");
		return -1;
	}	
	
	struct sockaddr_in s_addr={0};  //定义一个缓冲区 存放对方的IP地址信息
	int len = sizeof(s_addr);
	char buf[1024] = {0};//消息缓冲区

	udpData_t rec_data;

	//接收UDP数据 
	while(1)
	{
		recvfrom(udp_socket_fd, &rec_data, sizeof(rec_data), 0, (struct sockaddr *)&s_addr, &len);
		printf("[IP:%s,PORT:%d]", inet_ntoa(s_addr.sin_addr), ntohs(s_addr.sin_port)); //打印消息发送者的IP信息
		printf("type = %d, length = %d, srcip = %s, status = %d\n", ntohl(rec_data.type), ntohl(rec_data.length), rec_data.srcIp, ntohl(rec_data.status));
		if(strcmp(buf, "e") == 0)
		{
			break; 
		}
		bzero(&rec_data, sizeof(rec_data));
	}	
}

3.运行结果

         此功能主要调试十进制数据收发,相较于字符串收发的区别在于发送端需要借助htonl()函数进行转换,接收端需要借助ntohl()函数进行转换。此功能调试借鉴了其他博主分享的一些知识,得以调试成功,十分感谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值