【Linux学习笔记53】UDP服务器IO模型之信号驱动

引言

上一篇笔记简单介绍了UDP协议的用法,这篇笔记主要是使用信号驱动的方式获得IO的数据。那么,这种方式只使用于UDP,并不适用于TCP。因为,TCP需要建立连接,每产生一个事件都会触发信号,比如说连接,连接确认,数据确认,断开连接等事件,都会触发信号。因此,TCP对应的事件过多,需要大部分精力解释信号。

UDP异步信号的工作方式

在这里插入图片描述

  • 在应用层中会创建UDP的套接字,并且使用该套接字与硬件设备中进行数据交互
  • UDP协议的传输只用确定IP、PORT就可以通信了。但是套接字与其并不是一一对应的。
  • 进程会产生子进程,那么也会复制多一个UDP的套接字fd’,这个fd’也指向相同的IP和PORT
  • 当数据来到的时候,会触发SIGIO的信号,那么内核并不知道数据要发给那个套接字。
  • 因此,首先要注册一个处理SIGIO信号的函数
  • 然后设置SIGIO的属主,以至于收到数据后,将数据发送到指定的进程中
  • 使得fd工作在异步信号模式中

代码实现:

server.c:

#include "head4sock.h"

#define MAXSIZE 80

static int sockfd;
static char buf[MAXSIZE];
static struct sockaddr_in srvaddr, cliaddr;
static socklen_t addrlen = sizeof cliaddr;

void usage(const char *prog)
{
	fprintf(stderr, "Usage: %s <PORT>\n", prog);
	exit(0);
}

void catch_sig(int sig)
{
	bzero(&cliaddr, addrlen);
	bzero(buf, MAXSIZE);

	recvfrom(sockfd, buf, MAXSIZE, 0,
			(struct sockaddr *)&cliaddr, &addrlen);

	printf("msg from %s:%hu: %s",
			inet_ntoa(cliaddr.sin_addr),
			ntohs(cliaddr.sin_port),
			buf);
}

int main(int argc, char **argv)
{
	if(argc != 2)
		usage(argv[0]);

	sockfd = Socket(AF_INET, SOCK_DGRAM, 0);

	bzero(&srvaddr, sizeof srvaddr);
	srvaddr.sin_family = AF_INET;
	srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	srvaddr.sin_port = htons(atoi(argv[1]));

	Bind(sockfd, (struct sockaddr *)&srvaddr, sizeof srvaddr);

	// 1,注册SIGIO的处理函数,当信号来了调用catch_sig
	signal(SIGIO, catch_sig);

	// 2,设置SIGIO的属主
	fcntl(sockfd, F_SETOWN, getpid());

	// 3,使得sockfd工作在异步信号模式
#ifdef O_ASYNC //如果系统中有定义O_ASYNC则使用fcntl
	fcntl(sockfd, F_SETFL, O_ASYNC);
#else
	int on = 1;
	ioctl(sockfd, FIOASYNC, &on);
#endif

	while(1)
		pause();
}

client.c:

#include "head4sock.h"

#define MAXSIZE 80

void usage(const char *prog)
{
	printf("Usage: %s <IP><PORT>\n", prog);
	exit(1);
}

int main(int argc, char **argv)
{
	if(argc != 3)
		usage(argv[0]);

	int sockfd;
	sockfd = Socket(AF_INET, SOCK_DGRAM, 0);

	struct sockaddr_in srvaddr;
	srvaddr.sin_family = AF_INET;
	inet_pton(AF_INET, argv[1],
			(struct socaddr *)&srvaddr.sin_addr);
	srvaddr.sin_port = htons(atoi(argv[2]));

	char buf[MAXSIZE];
	socklen_t addrlen = sizeof srvaddr;
	while(1){
		bzero(buf, MAXSIZE);
		fgets(buf, MAXSIZE, stdin);
		sendto(sockfd, buf, strlen(buf), 0,
				(struct sockaddr *)&srvaddr, addrlen);
	}
}

代码运行结果

在这里插入图片描述

发布了91 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/RayCongLiang/article/details/100938515