目錄題目分析代碼結果 題目 小組實現,小組中的每位成員都需要設計程式,要求程式可以加入到一個多播組中並等待伺服器發送數據包,並且程式還需要具有發送功能,如果收到數據包則把消息內容輸出到終端, 消息內容格式 [消息來源IP 消息時間 ] : 消息內容 分析 1.發送端需設置套接字的廣播屬性,使用set ...
目錄
題目
小組實現,小組中的每位成員都需要設計程式,要求程式可以加入到一個多播組中並等待伺服器發送數據包,並且程式還需要具有發送功能,如果收到數據包則把消息內容輸出到終端, 消息內容格式 [消息來源IP 消息時間 ] : 消息內容
分析
1.發送端需設置套接字的廣播屬性,使用setsockopt()函數,第三個參數需添加SO_BROADCAST;
2.接收端需設置同一埠號並加入組播地址,才能接受同組發送的信息,也需要使用setsockopt()函數,第三個參數需添加IP_ADD_MEMBERSHIP。
代碼
/***********************************************************************************
*
* file name: udp_client.c
* author : [email protected]
* date : 2024/06/04
* function : 該案例是小組實現,小組中的每位成員都需要設計程式,要求程式可以加入到一個
* 多播組中並等待伺服器發送數據包,並且程式還需要具有發送功能,如果收到數據
* 包則把消息內容輸出到終端,消息內容格式 [消息來源IP 消息時間 ]:消息內容
* note : None
* version :
*
* CopyRight (c) 2023-2024 [email protected] All Right Reseverd
*
* **********************************************************************************/
/************************************頭文件*****************************************/
#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 <pthread.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
/***********************************************************************************/
/************************************全局變數***************************************/
int udp_socket; //UDP套接字
/***********************************************************************************/
/*************************************結構體****************************************/
typedef struct lcd_time
{
int year; //年
int mon; //月
int mday; //日
int wday; //星期
int hour; //時
int min; //分
int sec; //秒
}LcdTime;
/***********************************************************************************/
/***********************************************************************************
*
* name : GetTime
* function : 調用此函數可獲取開發板的時間
* param :
* none
*
* retval : char *
* author : [email protected]
* date : 2024/06/04
* note : None
* version :
*
* *********************************************************************************/
//獲取開發板時間
char *GetTime()
{
//申請堆記憶體並定義一個記錄LCD硬體時間的結構體指針
LcdTime *tstm = (LcdTime *)calloc(1,sizeof(LcdTime));
char * tstime = (char *)calloc(1,sizeof(char) * 32);
//錯誤處理
if (NULL == tstm)
{
printf("calloc for time failed\n");
return NULL;
}
//4.獲取當前系統時間,並把時間轉換為特定格式“yy年mm月dd日 星期x tt:mm:ss”
time_t Tseconds = time(NULL);
struct tm *ft = localtime(&Tseconds);
tstm->year = (ft->tm_year) + 1900; //年從1900年開始
tstm->mon = (ft->tm_mon) + 1; //月份從0開始
tstm->mday = (ft->tm_mday);
tstm->wday = (ft->tm_wday);
tstm->hour = (ft->tm_hour);
tstm->min = (ft->tm_min);
tstm->sec = (ft->tm_sec);
sprintf(
tstime,
"%d年%02d月%02d日,星期%d,%02d:%02d:%02d",
tstm->year,
tstm->mon,
tstm->mday,
tstm->wday,
tstm->hour,
tstm->min,
tstm->sec
);
//fwrite(data_buffer,BUFFRSIZE,1,fp);
return tstime;
}
/***********************************************************************************
*
* name : recv_udp_msg
* function : 子線程的任務函數,該函數用於接收伺服器發送的數據包
* param :
* none
*
* retval : none
* author : [email protected]
* date : 2024/06/04
* note : None
* version :
*
* *********************************************************************************/
void *recv_udp_msg(void *arg)
{
//1.需要先綁定伺服器的埠和地址
struct sockaddr_in host_addr;
host_addr.sin_family = AF_INET; //協議族,是固定的
host_addr.sin_port = htons(60000); //目標埠,必須轉換為網路位元組序
host_addr.sin_addr.s_addr = htonl(INADDR_ANY); //目標地址 "192.168.64.xxx" 已經轉換為網路位元組序 INADDR_ANY
bind(udp_socket,(struct sockaddr *)&host_addr, sizeof(host_addr));
//3.調用recvfrom等待接收數據,並且接收客戶端的網路信息
char buf[128] = {0};
char *p = (char *)calloc(1,sizeof(char) * 32) ;
struct sockaddr_in client;
socklen_t client_len = sizeof(client);
while(1)
{
p = GetTime();
recvfrom(udp_socket,buf,sizeof(buf), 0 ,(struct sockaddr *)&client,&client_len); //預設會阻塞
printf("[%s,%s]:%s\n",inet_ntoa(client.sin_addr),p,buf);
bzero(buf,sizeof(buf));
}
}
// 運行客戶端可執行文件 ./xxx 伺服器埠 伺服器地址
int main(int argc,char *argv[])
{
//檢查參數有效性
// if (argc != 3)
// {
// 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);
}
//設置組播選項
struct ip_mreqn mreqn;
mreqn.imr_multiaddr.s_addr = inet_addr("226.66.66.66"); //組地址
mreqn.imr_address.s_addr = htonl(INADDR_ANY); //本地地址 inet_addr("192.168.64.97")
mreqn.imr_ifindex = 0; //介面索引
setsockopt(udp_socket,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn));
//設置廣播屬性
int opt = 1;
setsockopt(udp_socket,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt));
//設置組播屬性
// setsockopt(udp_socket,IPPROTO_IP,IP_MULTICAST_TTL,&opt,sizeof(opt));
//2.創建子線程
pthread_t recv_thread;
pthread_create(&recv_thread,NULL,recv_udp_msg,NULL);
//2.向目標主機發送消息,需要設置目標埠和目標地址
char buf[128] = {0};
struct sockaddr_in dest_addr;
dest_addr.sin_family = AF_INET; //協議族,是固定的
dest_addr.sin_port = htons(60000); //伺服器埠,必須轉換為網路位元組序
dest_addr.sin_addr.s_addr = inet_addr("226.66.66.66"); //伺服器地址 "192.168.64.xxx"
//3.發送客戶端的上線時間
while(1)
{
scanf("%s",buf);
sendto(udp_socket,buf,strlen(buf),0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
}
return 0;
}