Linux网络编程——UDP服务器和广播/组播

16 篇文章 0 订阅
14 篇文章 0 订阅

学习笔记,小白可以相互学习,大佬看到能告诉咱理解不对的地方就好了。


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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值