基於c語言的UDP客戶端、服務端二合一基礎程式碼
示意圖:
準備好了嗎,以下是基礎程式碼:
/**************************************************************************************************************************************
*
* 位元組序:資料以位元組流的方式進行傳輸,底層都是採用二進位制,位元組流的順序是由架構決定的,現在假設使用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;
}