基于c语言的UDP客户端、服务端二合一基础代码

基于c语言的UDP客户端、服务端二合一基础代码

示意图:
image
如果你只是单纯的接收广播以内的:

/**************************************************************************************************************************************
 *
 *
 *
 *
 *	组播接收
 *
 *
 *
 *   h :host  主机/本地
 *   to:      转换
 *   n :net   网络
 *   l :long  长整型
 *   s :short 短整型
 *
 *   htons:把本地字节序的一个短整型转换为网络字节序
 *   htonl:把本地字节序的一个长整型转换为网络字节序
 *   ntohs:把网络字节序的一个短整型转换为本地字节序
 *   ntohl:把网络字节序的一个长整型转换为本地字节序
 * ***********************************************************************************************************************************/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <netinet/in.h>

int main(int argc, char *argv[])
{
	// 检查参数有效性
	if (argc != 2)
	{
		fprintf(stderr, "argument is invaild ,errno:%d,%s\n", errno, strerror(errno));
		exit(1);
	}

	// 1.创建UDP套接字
	int udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
	if (udp_socket == -1)
	{
		fprintf(stderr, "udp socket error,errno:%d,%s\n", errno, strerror(errno));
		exit(1);
	}

	//--------------------------------------------------------------------------------------------------
	// 2. 绑定服务器的端口和地址
	struct sockaddr_in host_addr;
	memset(&host_addr, 0, sizeof(host_addr));
	host_addr.sin_family = AF_INET;
	host_addr.sin_port = htons(atoi(argv[1]));	   // 使用命令行参数指定的端口
	host_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有网络接口

	if (bind(udp_socket, (struct sockaddr *)&host_addr, sizeof(host_addr)) == -1)
	{
		perror("bind error");
		exit(1);
	}
	//--------------------------------------------------------------------------------------------------
	//--------------------------------------------------------------------------------------------------
	//3.设置组播地址
	struct ip_mreq mreq;
	mreq.imr_multiaddr.s_addr = inet_addr("224.88.88.88"); // 组播地址
	mreq.imr_interface.s_addr = htonl(INADDR_ANY);		   // 本地网络接口
	setsockopt(udp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
	//--------------------------------------------------------------------------------------------------

	// 4. 调用recvfrom等待接收数据
	char buf[128] = {0};
	struct sockaddr_in client;
	socklen_t client_len = sizeof(client);

	while (1)
	{
		int bytes_received = recvfrom(udp_socket, buf, sizeof(buf), 0, (struct sockaddr *)&client, &client_len);
		if (bytes_received == -1)
		{
			perror("recvfrom error");
			continue;
		}

		printf("Received %d bytes from [%s]: %s\n", bytes_received, inet_ntoa(client.sin_addr), buf);
		bzero(buf, sizeof(buf));
	}
	//--------------------------------------------------------------------------------------------------
	return 0;
}

接收+发送结合的基础代码:

/**************************************************************************************************************************************
*
*   字节序:数据以字节流的方式进行传输,底层都是采用二进制,字节流的顺序是由架构决定的,现在假设使用X86架构,是采用小端存储
*	网络字节序:
*	本地字节序:
*
*	大端存储:低地址存储高字节   当数据超过1个字节的时候才需要区分大端还是小端  假设int型 0x12345678   0x12  | 0x34  | 0x56 |  0x78
*	小端存储:低地址存储低字节   当数据超过1个字节的时候才需要区分大端还是小端  假设int型 0x12345678   0x78  | 0x56  | 0x34 |  0x12
*
*	设备A采用X86架构,所以设备A采用小端存储  待发送的数据 :0x12345678
*   设备B采用ARM架构,所以设备B采用大端存储  待接收的数据 :?
*
*   为了统一发送数据的格式,所以互联网传输的数据统一采用大端方式,为了方便开发,linux系统提供了转换的接口:htonl、htons、ntohl、ntohs
*
*   h :host  主机/本地
*   to:      转换
*   n :net   网络
*   l :long  长整型
*   s :short 短整型
*
*   htons:把本地字节序的一个短整型转换为网络字节序
*   htonl:把本地字节序的一个长整型转换为网络字节序
*   ntohs:把网络字节序的一个短整型转换为本地字节序
*   ntohl:把网络字节序的一个长整型转换为本地字节序
* ***********************************************************************************************************************************/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <time.h>
#include <pthread.h>

#define  MULTICAST_ADDR "224.88.88.88"
//这里的宏定义是你自定义的广播组,如同聊天室需要在同一个频道

int udp_socket;

//客户端任务
void *client(void *arg)
{
	
	
		//2.向目标主机发送消息,需要设置目标端口和目标地址
		char buffer[128] = {0};
		
		struct sockaddr_in  dest_addr;
		dest_addr.sin_family 		= AF_INET; 						//协议族,是固定的
		dest_addr.sin_port   		= htons(9999);			//服务器端口,必须转换为网络字节序
		dest_addr.sin_addr.s_addr   = inet_addr(MULTICAST_ADDR);			//服务器地址 "192.168.64.xxx"  

		bind(udp_socket,(struct sockaddr *)&dest_addr, sizeof(dest_addr));//绑定服务器和端口

	while(1)
	{	
		printf("请输入内容:");
		scanf("%s",buffer);

		//3.发送客户端的上线时间
		sendto(udp_socket,buffer,strlen(buffer),0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
	}

}

int main(int argc,char *argv[])
{

	//检查参数有效性
	if (argc != 2)
	{
		fprintf(stderr, "argument is invaild ,errno:%d,%s\n",errno,strerror(errno));
		exit(1);
	}

	//1.创建UDP套接字             
	udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
	if (udp_socket == -1)
	{
		fprintf(stderr, "udp socket error,errno:%d,%s\n",errno,strerror(errno));
		exit(1);
	}


// 启用广播选项  
  
	//setsockopt(udp_socket, SOL_SOCKET, SO_BROADCAST, &broadcast, option_len);

	//getsockopt(udp_socket, SOL_SOCKET, SO_BROADCAST,(void *)&optval, &option_len);
  //----------------------------------------------------------------------------------------
	//2.需要先绑定服务器的端口和地址
	struct sockaddr_in  host_addr;

	struct ip_mreqn mreq;

	host_addr.sin_family 		= AF_INET; 						//协议族,是固定的
	host_addr.sin_port   		= htons(atoi(argv[1]));			//目标端口,必须转换为网络字节序
	host_addr.sin_addr.s_addr   = INADDR_ANY;		//目标地址 "192.168.64.xxx"  已经转换为网络字节序  INADDR_ANY

	bind(udp_socket,(struct sockaddr *)&host_addr, sizeof(host_addr));

  //----------------------------------------------------------------------------------------
	//加入多播组
    mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_ADDR);  
    mreq.imr_address.s_addr= htonl(INADDR_ANY); // 或者指定网络接口地址
	mreq.imr_ifindex = 0;
    setsockopt(udp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
  //----------------------------------------------------------------------------------------
    //创建客户端线程
	pthread_t hostser;
	pthread_create(&hostser,NULL,client,NULL);

    

	//3.调用recvfrom等待接收数据,并且接收客户端的网络信息
	char buf[128] = {0};
	struct sockaddr_in  client;
	socklen_t client_len = sizeof(client);

	while(1)
	{   
	    
		recvfrom(udp_socket,buf,sizeof(buf), 0 ,(struct sockaddr *) &client,&client_len); //默认会阻塞

		 // 输出消息内容  
        time_t now = time(NULL);  
        printf("client ip is [%s]  time:%s  %s\n", inet_ntoa(client.sin_addr), ctime(&now),buf);  
		bzero(buf,sizeof(buf));
	}
	
	return 0;

}

posted @ 2024-06-05 20:13  周半仙  阅读(273)  评论(0)    收藏  举报