Linux network programming practice four (UDP broadcast)

topic:

Programming Practice 4 :Design and develop a broadcast server to broadcast messages to the subnet where the server is located. The server program regularly reads the information that needs to be broadcast from the broadcast information file, and broadcasts the information according to the specified release time of the information. Design and develop the client, receive broadcast messages, and print out to the monitor.

It is required to use C/C++ to compile and submit the program source code ; the program function is complete and correct, the source code is well formatted, properly commented, and the module division is reasonable.

Screenshot of test effect:

        Because it takes a long time to wait for the information to be broadcast according to the specified release time, it is not convenient to test, so my broadcast information file is written as follows:

        The number before the colon (:) is used to represent the time in seconds. After the colon is the information to broadcast (spaces are stripped). If the number before the colon is n, then after sending a broadcast message, the server will temporarily pause for n seconds (using the sleep function).

        In addition, because the client needs to bind the port when broadcasting, generally one port can only be bound to one program, so the broadcast can only be one-to-one, so when I set the broadcast on the client, I also set the port multiplexing Use, so that multiple clients can receive the message sent by the server:

        Let's start the formal test

        As shown in the figure, when the client receives the message, it will display the received time. For the convenience of testing, I set up the server to continuously read the broadcast file for broadcast, and the interval between each broadcast is 5s. After each broadcast, the time of this broadcast will be displayed.

        Compare the broadcast file with the time when the client receives the information:

        It can be seen that the time when the client receives the message is consistent with the time when the file is received.

        Next run multiple clients for testing:

        It can be seen that because port multiplexing is set, it is possible to broadcast to multiple clients.

        The test is complete.

Program source code:

Server code:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>	
#include <string.h>	
#include <netinet/in.h>
#include <unistd.h>	
#include <arpa/inet.h>
#include <pthread.h>	
#include <stdbool.h>
#include <sys/stat.h>
#include <fcntl.h>

#define broadcast_ip "192.168.110.255"//设置广播地址,必须为本机/虚拟机的广播地址才行
#define broadcast_port 8080 //设置广播端口
#define buff_len 1024	//设置缓冲区长度
#define Maxline 1024	//设置最大读取文件行数

char buffer[buff_len];//缓冲区

int get_time();//将buffer前面的数字提取出来,作为暂停时间
void get_char();//从buffer中要发送的信息提取出来,

int main(int argc,void *argv[])
{
	int err;	//用来返回错误信息
	int t;		//用来表示每次发送信息后暂停的时间(单位是秒)
	struct sockaddr_in broadcast_addr;  //创建一个地址结构
	char message[buff_len]={0};//用来发送消息
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);   //创建套接字
	if(sockfd < 0){	/*出错*/
		printf("socket error");
		return -1;
	}

	//开启广播
	int opt =1;
	err = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));//将套接字设置为广播模式
	if(err < 0) {	/*出错*/
		printf("setsockopt error");
		return -1;
	}
	
	memset(&broadcast_addr, 0, sizeof(broadcast_addr)); //初始化为0
	broadcast_addr.sin_family = AF_INET;//初始化地址族IPV4
	broadcast_addr.sin_port = htons(broadcast_port); //设置端口号(网络字节序号)
	broadcast_addr.sin_addr.s_addr = inet_addr(broadcast_ip);//初始化绑定地址, 用INADDR_ANY--表示绑定本机地址
	int k=1;
	//读取文件发送数据
	while(1){
		FILE* fp=fopen("test.txt","r");//以只读的方式打开文件
		if(fp == NULL){
			printf("failed to open file\n");
			break;
		}
		int time_sum=0;//记录本次广播所花的时间
		printf("------第 %d 次广播------\n",k);
		while(fgets(buffer,Maxline,fp)){//以行为单位读取文件并将数据发送到客户端
			t=get_time(buffer);
			time_sum+=t;
			//strcpy(message,get_char(buffer));
			get_char();
			strcpy(message,buffer);
			err = sendto(sockfd, message, sizeof(message), 0, (struct sockaddr*)&broadcast_addr, sizeof(broadcast_addr));
			if(err <0){
				printf("sendto error");	//发送错误,关闭连接后结束程序
				//close(sockfd);
				continue;
			}
			memset(buffer,0,buff_len);//清空缓存区
			memset(message,0,buff_len);
			sleep(t);	//暂停ts
		}
		fclose(fp);	//关闭文件指针
		k++;
		printf("本次广播共花时间%d秒\n",time_sum);
		sleep(5);//暂停5s
	}
	close(sockfd);	//关闭套接字
	return 0;
}

int get_time(char s[])//将一行字符串前面的数字提取出来,作为暂停时间
{
	int t=0;
	for(int i=0;i<strlen(s);i++)
		if(s[i]>='0'&&s[i]<='9') t=t*10+s[i]-'0';
		else if(s[i]==':') break;
	return t;
}

void get_char()//将buffer中要发送的信息提取出来
{
	char s[buff_len];
	strcpy(s,buffer);
	memset(buffer,0,buff_len);//清空
	int i=0,j=0;
	while(s[i]!=':')i++;
	i++;
	while(s[i]==' ')i++;
	for(;i<strlen(s);i++)buffer[j++]=s[i];
	//printf("%s\n",buffer);
}

Client code:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#include <semaphore.h>
#include <stdbool.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <time.h>
#define MAXSIZE 100

#define broadcast_port 8080 //设置广播端口
#define buff_len 1024	//设置缓冲区长度

int main(void)
{
	int err; //错误信息
	char buffer[buff_len]={0},message[buff_len]={0};//创建数据缓冲区
	struct sockaddr_in client_addr;  //客户端地址结构
	struct sockaddr_in server_addr;	//服务端地址结构
	socklen_t len = sizeof(server_addr);  //服务端地址结构长度
	struct tm *p;
	time_t t;	//用于显示当前时间
	time(&t);
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);//创建套接字 UDP--SOCK_DGRAM
	if(sockfd < 0){/*出错*/
		printf("socket error\n");
		return -1;
	}
	
	//设置端口复用SO_REUSEADDR
	int opt = 1;
	err  = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
	if(err < 0) {	/*出错*/
		printf("setsockopt error");
		return -1;
	}
	
	memset(&client_addr, 0, sizeof(client_addr)); //初始化为0
	client_addr.sin_family = AF_INET;//初始化地址族IPV4
	client_addr.sin_port = htons(broadcast_port); //设置端口号(网络字节序号)
	client_addr.sin_addr.s_addr = INADDR_ANY;//初始化绑定地址, 用INADDR_ANY--表示绑定本机地址
	
	err = bind(sockfd, (struct sockaddr*)&client_addr, sizeof(client_addr));//地址绑定
	if(err < 0){/*出错*/
		printf("bind error\n");
		return -1;
	}
	
	//接收数据
	while(1){
		memset(buffer,0,sizeof(buffer));//清零
		err = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &len);
		if(err < 0){
				printf("recvfrom error\n");
				close(sockfd);
				return -1;
		}
		time(&t);//获取当前时间
		p=gmtime(&t);//
		//构造时间进行输出
		sprintf(message,"%d-%d-%d %02d:%02d:%02d", 1900+p->tm_year,1+p->tm_mon, p->tm_mday,8+p->tm_hour,p->tm_min, p->tm_sec);
		printf("当前时间:%s,接收到消息:\n",message);
		printf("%s\n", buffer);
	}
	
	//关闭套接字
	close(sockfd);
	return 0;
}

Contents of the broadcast information file test.txt:

1:hello,client,i am server
2:welcome to udp broadcast
3:this is a test!
4:yes,hhhhhhhhhh
4:you don't need to reply
3:just a test
5:    don't worry

epilogue

        The practice this time is relatively simple, but I still did it for a long time, doing it on and off, not in the state. Otherwise, it can be done in half a day.

        The test was tested on a virtual machine, and then I used QQ to capture the picture. I don’t know why it’s a bit blurry, but I can probably see it.

        Unexpectedly, what I did slowly was still commented by the teacher. The teacher said that I did not do it according to the requirements of the topic.

        The teacher also said that I can think of port multiplexing, which means that I did it, found the problem and solved the problem, but the many in the broadcast one-to-many does not refer to multiple programs on one host, but multiple Host, so port multiplexing is actually not needed.

        Well, although I didn't complete the topic, the teacher still gave me a high score, thank you teacher (><)

        I didn't deal with the time issue mentioned at the end, because it had already been submitted at that time (it cannot be submitted repeatedly), and I was lazy, so I didn't change it. Everyone is interested to solve it~

Guess you like

Origin blog.csdn.net/xiexieyuchen/article/details/129815733