多种I/O函数

send&recv函数

 不同操作系统对上述可选项的支持也不同。对表中一部分(主要是不受操作系统差异影响的)进行记录:

MSG_OOB:发送紧急消息

紧急消息的传输只需在调用send函数时指定MSG_OOB选项即可。

//oob_send
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define BUF_SIZE 30
void error_handling(char *message);

int main(int argc, char *argv[])
{
	int sock;
	struct sockaddr_in recv_adr;

	if(argc!=3) {
		printf("Usage : %s <IP> <port>\n", argv[0]);
		exit(1);
	 }

	sock=socket(PF_INET, SOCK_STREAM, 0);
 	memset(&recv_adr, 0, sizeof(recv_adr));
	recv_adr.sin_family=AF_INET;
	recv_adr.sin_addr.s_addr=inet_addr(argv[1]);
	recv_adr.sin_port=htons(atoi(argv[2]));
  
	if(connect(sock, (struct sockaddr*)&recv_adr, sizeof(recv_adr))==-1)
		error_handling("connect() error!");
	
	write(sock, "123", strlen("123"));
	send(sock, "4", strlen("4"), MSG_OOB);  //设置紧急传输
	write(sock, "567", strlen("567"));
	send(sock, "890", strlen("890"), MSG_OOB);
	close(sock);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

紧急消息的接收

带外数据

  带外数据用于迅速告知对方本端发生的重要的事件。它比普通的数据(带内数据)拥有更高的优先级,不论发送缓冲区中是否有排队等待发送的数据,它总是被立即发送。带外数据的传输可以使用一条独立的传输层连接,也可以映射到传输普通数据的连接中。实际应用中,带外数据是使用很少见,有,telnet和ftp等远程非活跃程序。
  UDP没有没有实现带外数据传输,TCP也没有真正的带外数据。不过TCP利用头部的紧急指针标志和紧急指针,为应用程序提供了一种紧急方式,含义和带外数据类似。TCP的紧急方式利用传输普通数据的连接来传输紧急数据。

  内核通知应用程序带外数据到达的方式有两种:一种就是利用IO复用技术的系统调用(如select)在接受到带外数据时将返回,并向应用程序报告socket上的异常事件。另一种方法就是使用SIGURG信号。

//oob_recv
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>

#define BUF_SIZE 30
void error_handling(char *message);
void urg_handler(int signo);

int acpt_sock;
int recv_sock;
int main(int argc, char *argv[])
{
	struct sockaddr_in recv_adr, serv_adr;
	int str_len, state;
	socklen_t serv_adr_sz;
	struct sigaction act;
	char buf[BUF_SIZE];

	if(argc!=2) {
		printf("Usage : %s <port>\n", argv[0]); 
		exit(1);	
	 }
	//收到MSG_OOB紧急消息时,操作系统将产生SIGURG信号,并调用注册的信号处理函数
	act.sa_handler=urg_handler; //设置信号处理函数
	sigemptyset(&act.sa_mask); 
	act.sa_flags=0; 
	
	acpt_sock=socket(PF_INET, SOCK_STREAM, 0);
	memset(&recv_adr, 0, sizeof(recv_adr));
	recv_adr.sin_family=AF_INET;
	recv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
	recv_adr.sin_port=htons(atoi(argv[1]));

	if(bind(acpt_sock, (struct sockaddr*)&recv_adr, sizeof(recv_adr))==-1)
		error_handling("bind() error");
	listen(acpt_sock, 5);

	serv_adr_sz=sizeof(serv_adr);
	recv_sock=accept(acpt_sock, (struct sockaddr*)&serv_adr, &serv_adr_sz);
	//fcntl(recv_sock,F_SETOWN,getpid())  将文件描述符recv_sock
	//getpid()用来取得目前进程的进程识别码(PID)
	fcntl(recv_sock, F_SETOWN, getpid()); 
	state=sigaction(SIGURG, &act, 0);
	
	while((str_len=recv(recv_sock, buf, sizeof(buf), 0))!= 0) 
	{
		if(str_len==-1)
			continue;
		buf[str_len]=0;
		puts(buf);
	}
	close(recv_sock);
	close(acpt_sock);
	return 0; 
}

void urg_handler(int signo)
{
	int str_len;
	char buf[BUF_SIZE];
	str_len=recv(recv_sock, buf, sizeof(buf)-1, MSG_OOB);
	buf[str_len]=0;
	printf("Urgent message: %s \n", buf);
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

  此处,fcntl函数将文件描述符recv_sock指向的套接字引发的SIGURG信号处理进程变为将getpid函数返回值用作ID的进程。处理SIGURG信号时必须指定处理信号的进程,而getpid函数返回调用此函数的进程ID,上诉调用语句指定当前进程为处理SIGURG信号的主体。

  根据运行的结果,事实上,通过MSG_OOB可选项传递数据时并不会加快数据传输速度,而且通过信号处理函数urg_handler读取数据时也只能读1个字节。剩余字节数据只能通过未设置MSG_OOB可选项的普通输入函数读取。

紧急模式工作原理

在oob_send.c中调用:

send(sock, "890", strlen("890"), MSG_OOB);

此时的输出缓冲状态:

  紧急消息的意义在于督促消息处理,而非紧急传输形式受限的消息。

检查输入缓冲

  设置MSG_PEEK选项并调用recv函数时,即使读取了输入缓冲的数据也不会删除;设置了MSG_DONTWAIT选项,保证即使不存在待读取数据也不会进入阻塞状态。

readv & writev 函数

  readv 和 writev函数可对数据进行整合传输和发送,通过writev函数可以将分散保存在多个缓冲中的数据一并发送,通过readv函数可以由多个缓冲分别接收。适当使用这2个函数可以减少I/O函数的调用次数。

 

#include <stdio.h>
#include <sys/uio.h>

int main(int argc, char *argv[])
{
	struct iovec vec[2];
	char buf1[]="ABCDEFG";
	char buf2[]="1234567";
	int str_len;

	vec[0].iov_base=buf1;
	vec[0].iov_len=3;
	vec[1].iov_base=buf2;
	vec[1].iov_len=4;

	str_len=writev(1, vec, 2);
	//使用 puts() 显示字符串时,系统会自动在其后添加一个换行符
	puts(""); //此处为了添加换行符
	printf("Write bytes: %d \n", str_len);
	return 0;
}

 

#include <stdio.h>
#include <sys/uio.h>
#define BUF_SIZE 100

int main(int argc, char *argv[])
{
	struct iovec vec[2];
	char buf1[BUF_SIZE]={0,};
	char buf2[BUF_SIZE]={0,};
	int str_len;
//第一块区域保存不下的会保存到第二块区域
	vec[0].iov_base=buf1;
	vec[0].iov_len=5;  
	vec[1].iov_base=buf2;
	vec[1].iov_len=BUF_SIZE;

	str_len=readv(0, vec, 2);
	printf("Read bytes: %d \n", str_len);
	printf("First message: %s \n", buf1);
	printf("Second message: %s \n", buf2);
	return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值