Linux網絡編程——UDP服務器和廣播/組播

學習筆記,小白可以相互學習,大佬看到能告訴咱理解不對的地方就好了。


UDP服務器流程:

1.socket

2.bind

3.具體操作(write/read/recvfrom/sebdto)

UDP客戶端流程:

1.socket

2.bind(可選)

3.具體操作(write/read/recvfrom/sebdto)


/******client.c************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

int main()
{
	int ret;
	int sockfd;
	char buf[256];
	struct sockaddr_in srvaddr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd == -1) {
		perror("socket");
		return -1;
	}
	memset(&srvaddr, 0, sizeof(struct sockaddr_in));
	srvaddr.sin_family = AF_INET;
	srvaddr.sin_port = htons(9999);
	srvaddr.sin_addr.s_addr = inet_addr("192.168.2.100");

	while(1) {
		fgets(buf, sizeof(buf), stdin);
		ret = sendto(sockfd, buf, sizeof(buf), 0, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
		if (ret == -1) {
			perror("sendto");
			return -1;
		}

		memset(buf, 0, sizeof(buf));
		ret = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);
		if (ret == -1) {
			perror("recvfrom");
			return -1;
		}
		printf("buf : %s\n", buf);

	}
	return 0;
}


/*****server.c*************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

int main()
{
	int ret;
	int sockfd;
	char buf[256];
	struct sockaddr_in srvaddr;
	struct sockaddr_in cltaddr;
	socklen_t addrlen;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd == -1) {
		perror("socket");
		return -1;
	}

	memset(&srvaddr, 0, sizeof(struct sockaddr_in));
	srvaddr.sin_family = AF_INET;
	srvaddr.sin_port = htons(9999);
	srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	ret = bind(sockfd, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
	if (ret == -1 ) {
		perror("bind");
		return -1;
	}
	
	while(1) {
		memset(buf, 0, sizeof(buf));
		addrlen = sizeof(struct sockaddr);
		ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&cltaddr, &addrlen);
		if (ret == -1) {
			perror("recvfrom");
			return -1;
		}
		printf("buf : %s\n", buf);
		sleep(10);
		ret = sendto(sockfd, buf, sizeof(buf), 0, (const struct sockaddr *)&cltaddr, addrlen);
		if (ret == -1) {
			perror("sendto");
			return -1; 
		} 
	}
	return 0;
}

網絡信息檢索函數:

1.gethostname()獲得主機名

2.getpeername()獲得與套接口相連的遠程協議地址

3.getsockname()獲得本地套接口協議地址

4.gethostbyname()根據主機名取得主機信息

5.gethostbyaddr()根據主機地址取得主機信息

6.getprotobyname()根據協議名取得主機協議信息

7.getprotrbynumber()根據協議號取得主機協議信息

8.getserverbyname()根據服務名取得相關服務信息

9.getserverbyport()根據端口號取得相關服務信息

10.getsockopt()/setsockopt()獲取/設置一個套接口選項

11.ioctl()/fcntl()設置套接口工作方式



網絡超時檢測

1.設置socket的屬性SO_RCVTIMEO

參考代碼:

struct tumeval tv;

tv.tv_sec = 5;//設置5秒時間,單位s

tv.t._usec = 0;//設置時間0ms,單位ms

setsockopt(sockfd,SOL_RCVTINMEO,&tv,sizeof(tv));//設置接收超時

recv()/recvfrom()/write()/read;//具體操作...,從socket讀取或者接收數據


2.用select檢測socket是否‘ready’

參考代碼:
struct fd_set radfs;

struct timeval tv = {5,0};//設置5秒時間

FD_ZERO(&rdfs);

FD_SET(sockfd,&rdfs);

if(select(sockfd+1,&rdfs,NULL,NULL,&tv) > 0)//socket就緒

{

recv()/recvfrom()/write()/read;//具體操作...,從socket讀取或者接收數據

}


3.設置定時器(timer),捕捉SIGALRM信號

參考代碼:

void handler()int signo   {return ;}//一旦進程收到這個信號,執行完信號處理函數之後,下一個函數就會直接返回,不阻塞在哪裏

struct sigaction act;

sigaction(SIGALRM.NULL,&act);

act.sa_handler = handler;

act.sa_flags &= ~SA_RESTART;

sigaction(SIGALRM,&act,NULL);

alarm(5);

if(recv(...)  < 0).....


廣播(broadcast)

前面介紹的數據包發送方式只有一個接受方,稱爲單播。

  如果同時發給局域網中的所有主機,稱爲廣播。

  只有用戶數據報(使用UDP協議)套接字才能廣播。


int setsockopt(int sockfd,int level,i

nt optname,const void *optval,socklen_t optelen)

level:指定控制套接字的層次可以取三種值:

1.SOL_SOCKET通用套接字選項    2.IPPROTO_IP:  ip選項     3.IPPROTO_TCP:  tcp選項

optname:存放選項值的緩衝區首地址

optlen:緩衝區首地址

optval:獲得或者設置套接字選項,根據選項名稱的數據類型進行轉換。

返回值:成功:0,失敗:-1,並設置errno



廣播發送:

1.創建用戶數據報套接字

2.缺省創建的套接字不允許廣播數據包,需要設置屬性(setsockopt可以設置套接字屬性)

3.接收方地址指定爲廣播地址(a.指定端口信息  b.發送數據包)

廣播接收:

1.創建用戶數據報套接字

2.綁定IP地址(廣播IP或者0.0.0.0)和端口

3.等待接收數據

/*******server.c************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

int main()
{
	int ret;
	int sockfd;
	char buf[256];
	struct sockaddr_in srvaddr;
	struct sockaddr_in cltaddr;
	socklen_t addrlen;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd == -1) {
		perror("socket");
		return -1;
	}

	memset(&srvaddr, 0, sizeof(struct sockaddr_in));
	srvaddr.sin_family = AF_INET;
	srvaddr.sin_port = htons(9999);
	srvaddr.sin_addr.s_addr = inet_addr("192.168.2.255");
	ret = bind(sockfd, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
	if (ret == -1 ) {
		perror("bind");
		return -1;
	}
	
	while(1) {
		memset(buf, 0, sizeof(buf));
		addrlen = sizeof(struct sockaddr);
		ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&cltaddr, &addrlen);
		if (ret == -1) {
			perror("recvfrom");
			return -1;
		}
		printf("buf : %s\n", buf);
	}
	return 0;
}


/*******client.c*************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

int main()
{
	int ret;
	int sockfd;
	char buf[256];
	struct sockaddr_in srvaddr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd == -1) {
		perror("socket");
		return -1;
	}

	/* 允許發送廣播 */
	int opt = 1;
	setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));

	memset(&srvaddr, 0, sizeof(struct sockaddr_in));
	srvaddr.sin_family = AF_INET;
	srvaddr.sin_port = htons(9999);
	srvaddr.sin_addr.s_addr = inet_addr("192.168.2.255");

	while(1) {
		fgets(buf, sizeof(buf), stdin);
		ret = sendto(sockfd, buf, sizeof(buf), 0, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
		if (ret == -1) {
			perror("sendto");
			return -1;
		}
	}
	return 0;
}


組播(multcast)

單播方式只能發給一個接收方

廣播方式發送給所有的主機。過多的廣播會大量佔用網絡帶寬,造成廣播風暴,影響正常通信

組播(也叫多播)是一種折中的方式。只有加入某個多播組的主機才能收到數據

網絡地址的D類地址是組播地址:不分網絡地址和主機地址,第一字節的前4位固定爲1110,224.0.0.1~239.255.255.255


組播發送:

1.創建用戶數據報套接字

2.接收方地址指定爲組播地址

3.指定端口信息

4.發送數據包


組播接收:

1.創建用戶數據報套接字

2.加入組播組

3.綁定IP地址(加入的組的組IP或者0.0.0.0)和端口

4.等待接收數據


/*****server.c************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

int main()
{
	int ret;
	int sockfd;
	char buf[256];
	struct sockaddr_in srvaddr;
	struct sockaddr_in cltaddr;
	socklen_t addrlen;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd == -1) {
		perror("socket");
		return -1;
	}
    //加入組播組
	struct ip_mreqn mrq;
	memset(&mrq, 0, sizeof(mrq));
	mrq.imr_multiaddr.s_addr = inet_addr("224.10.10.1");
	mrq.imr_address.s_addr = htonl(INADDR_ANY);
	setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mrq, sizeof(mrq));
	//bind
	memset(&srvaddr, 0, sizeof(struct sockaddr_in));
	srvaddr.sin_family = AF_INET;
	srvaddr.sin_port = htons(9999);
	srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	ret = bind(sockfd, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
	if (ret == -1 ) {
		perror("bind");
		return -1;
	}
	printf("dsdgfsdg\n");
	
	while(1) {
		memset(buf, 0, sizeof(buf));
		addrlen = sizeof(struct sockaddr);
		ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&cltaddr, &addrlen);
		if (ret == -1) {
			perror("recvfrom");
			return -1;
		}
		printf("buf : %s\n", buf);
	}
	return 0;
}


/*****client.c**************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

int main()
{
	int ret;
	int sockfd;
	char buf[256];
	struct sockaddr_in srvaddr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd == -1) {
		perror("socket");
		return -1;
	}
	memset(&srvaddr, 0, sizeof(struct sockaddr_in));
	srvaddr.sin_family = AF_INET;
	srvaddr.sin_port = htons(9999);
	srvaddr.sin_addr.s_addr = inet_addr("224.10.10.1");

	while(1) {
		fgets(buf, sizeof(buf), stdin);
		ret = sendto(sockfd, buf, sizeof(buf), 0, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
		if (ret == -1) {
			perror("sendto");
			return -1;
		}
		printf("ret = %d\n", ret);
	}
	return 0;
}



發佈了31 篇原創文章 · 獲贊 21 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章