• udp套接字使用信号驱动式I/O


    信号驱动式I/O的本质就是:进程预先告知内核当某个描写叙述符发生事件时,内核会向该进程发送SIGIO信号通知进程,进程可在信号处理函数中进行处理


    进程能够通过fcntl打开O_ASYNC标志或ioctl打开FIOASYNC标志来通知内核,二者的差别是一些系统不支持fcntl,所以应尽量使用ioctl


    对于TCP套接字产生SIGIO信号的条件:
    1.监听套接字上有新连接请求完毕
    2.某个断连请求发起
    3.某个断连请求完毕
    4.数据到达套接字
    5.数据已从套接字发送走(输出缓冲区有空暇空间)
    6.发生某个异步错误


    对于UDP套接字产生SIGIO信号的条件:
    1.数据报到达套接字
    2.套接字上发生异步错误


    对于套接字而言:TCP套接字和UDP套接字致使内核产生SIGIO信号的条件有所不同,当中TCP可产生该信号的条件较多,而UDP套接字产生该信号的条件仅仅有两个,由于我们无法得知详细是什么事件导致内核产生该信号。

    。对于UDP套接字产生该信号条件的推断就简单的多。这也是信号驱动式I/O主要用于UDP套接字的原因。




    套接字使用信号驱动式I/O的步骤:
    1.建立SIGIO信号处理函数
    2.设置设置套接字属主(使用fcntl的F_SETOWN命令)
    3.开启信号驱动式I/O(fcntl打开O_ASYNC 或 ioctl打开FIOASYNC)


    实例:
    客户每隔1秒钟将系统时间发送到server,server通过SIGIO信号处理函数中接收数据


    net.h

    #ifndef MY_NET_H  
    #define MY_NET_H  
          
    #include <sys/types.h>        
    #include <sys/socket.h>  
    #include <stdio.h>  
    #include <stdlib.h>  
    #include <arpa/inet.h>  
    #include <unistd.h>  
    #include <time.h>  
    #include <string.h>  
    #include <sys/select.h>  
    #include <sys/time.h>  
    #include <errno.h>
    #include <signal.h>
    #include <iostream>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <net/if.h>
    #include <net/if_arp.h>
    #include <sys/ioctl.h>
    #include <sys/ioctl.h>
    
    using namespace std;
    
    char recvBuf[1025];
    int listenfd;
    
    static void sigio_handler(int signo)
    {
    	if (signo != SIGIO)
    		return;
    	
    	int ret;
    	while (1)
    	{
    		ret = recvfrom(listenfd, recvBuf, sizeof(recvBuf),
    				   0, NULL, NULL);
    		if (ret < 0)
    		{
    			if (errno == EWOULDBLOCK)
    				break;
    				
    			perror("recvfrom error");
    			exit(-1);
    		}			
    	
    		cout << recvBuf << endl;
    	}
    }
    
    void init(int skfd)
    {
    	int ret;
    
    	//1.建立SIGIO信号的处理函数
    	signal(SIGIO, sigio_handler);
    	
    	//2.设置该套接字的属主
    	ret = fcntl(skfd, F_SETOWN, getpid());
    	if (ret < 0)
    	{
    		perror("fcntl error");
    		exit(-1);
    	}
    	
    	//3.开启该套接字的信号驱动式I/O
    	int on = 1;
    	ret = ioctl(skfd, FIOASYNC, &on);
    	if (ret < 0)
    	{
    		perror("ioctl error");
    		exit(-1);
    	}
    }
    
    int prepare()
    {
    	int skfd = socket(AF_INET, SOCK_DGRAM, 0);
    	if (skfd < 0)
    		return -1;
    	
    	struct sockaddr_in saddr;
    	bzero(&saddr, sizeof(saddr));
    	saddr.sin_family = AF_INET;
    	saddr.sin_port = htons(9999);
    	saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    	
    	if (bind(skfd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0)
    		return -1;
    	
    	return skfd;
    }
    
    #endif


    客户:

    #include "net.h"
    
    int main()
    {
    	int skfd;
    	skfd = socket(AF_INET, SOCK_DGRAM, 0);
    	if (skfd < 0)
    	{
    		perror("socket error");
    		exit(-1);
    	}
    
    	int ret;
    	time_t tm;
    	struct sockaddr_in desAddr;
    	bzero(&desAddr, sizeof(desAddr));
    	desAddr.sin_family = AF_INET;
    	desAddr.sin_port = htons(9999);
    	desAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    	
    	while (1)
    	{	
    		time(&tm);
    		ret = sendto(skfd, ctime(&tm), strlen(ctime(&tm)), 0,
    					 (struct sockaddr*)&desAddr, sizeof(desAddr));
    		if (ret < 0)
    		{
    			perror("");
    			exit(-1);
    		}
    		sleep(1);
    	}
    
    	return 0;
    }

    server:

    #include "net.h"
    
    int main()
    {
    	listenfd = prepare();
    	if (listenfd < 0)
    	{
    		perror("prepare error");
    		exit(-1);
    	}
    	
    	init(listenfd);
    	while(1);
    		
    	return 0;
    }
    





  • 相关阅读:
    Spring框架 基础01
    Mybatis框架 基础
    字节流,字符流
    集合的应用(练习:学生档案)
    集合
    时间类型的格式化(字符串和时间类型 之间的相互转换)
    逢三退一(boolean数组的使用)
    电子宠物(线程,实现方法)
    点是否在圆里
    sqlserver 指定上月25-本单据日期/本月24 数据汇总的保存后存储过程
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5348087.html
Copyright © 2020-2023  润新知