引言
上一篇笔记简单介绍了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);
}
}