【Linux编程】用select处理普通数据和带外数据

        传输层的TCP协议有带外数据的概念,带外数据又称为紧急数据,它比普通数据有更高的优先级,一般会立即发送,而不会排队等待。

        在TCP协议头部结构中有URG标志位和16位的紧急指针,若URG标志位被设置,表示紧急指针有效,此时紧急指针将指向紧急数据的下一个字节。

        带外数据只有一个字节大小,因为服务器将读取到的带外数据存入一个特殊的缓冲区,这个缓冲区只有一个字节的大小,并且带外数据会将TCP字节流截断,可以用带MSG_OOB标志的recv系统调用来读取带外数据,

        在网络编程中,select能监听可读,可写和异常事件,但能监听的异常事件只有一种,那就是socket上接收到带外数据。socket上接收到普通数据和带外数据都将使select返回,但前者处于可读状态,后者处于异常状态。


        用select处理普通数据和带外数据的代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[]){
	
	if(argc!=3) printf("格式:%s  <端口号>\n", argv[0]), exit(-1);
	
	int servfd = socket(AF_INET, SOCK_STREAM, 0);
	if(servfd==-1) printf("socket 失败!:%m\n"), exit(-1);
	printf("socket 成功!\n");
	
	/*封装serv端ip地址和端口号*/ 
	const char *ip = argv[1];
	int port = atoi(argv[2]);
	struct sockaddr_in serv;
	serv.sin_family = AF_INET;
	serv.sin_port = htons(port);
	inet_pton(AF_INET, ip, &serv.sin_addr);
	
	int r = bind(servfd, (struct sockaddr*)*serv, sizeof(serv));
	if(r==-1) printf("bind 失败!:%m\n"), exit(-1);
	printf("bind 成功!\n");
	
	r = listen(servfd, 5);
	if(r==-1) printf("listen 失败!:%m\n"), exit(-1); 
	printf("listen 成功!\n");
	
	/*用于封装连接到的cli端ip地址和端口号*/ 
	struct sockaddr_in cli;
	socklen_t cli_len = sizeof(cli);
	
	int clifd = accept(servfd, (struct sockaddr*)&cli, &cli_len);
	if(clifd==-1) printf("accept 失败!:%m\n"), exit(-1);	
	printf("accept 成功!\n");
	
	/*定义可读描述符集合和异常描述符集合,以及用户接收缓冲区*/ 
	fd_set readfd, exceptfd;
	char buf[1024];
	
	while(1){ 
		/*每次循环前清空readfd和exceptfd,然后在这两个描述符集合中重新设置clifd描述符*/ 
		FD_ZERO(&readfd);
		FD_ZERO(&exceptfd);
		FD_SET(clifd, &readfd);
		FD_SET(clifd, &exceptfd);
		memset(buf, 0, sizeof(buf));
		
		r = select(clifd+1, &readfd, NULL, &exceptfd, NULL);
		if(r==-1) printf("select 失败!:%m\n"), exit(-1);
		
		if(FD_ISSET(clifd, &readfd)){
			r = recv(clifd, buf, sizeof(buf), 0);
			if(r==-1) printf("recv普通数据出错!:%m\n"), exit(-1); 
			printf("收到%d字节普通数据:%s\n", r, buf);
		}
		
		/*接收带外数据需要用MSG_OOB标志*/
		if(FD_ISSET(clifd, &exceptfd)){
			r = recv(clifd, buf, sizeof(buf), MSG_OOB);
			if(r==-1) printf("recv带外数据出错!:%m\n"), exit(-1);
			printf("收到%d字节带外数据:%s\n", r, buf);
		}
	}
	
	close(clifd);
	close(servfd);
	return 0;
}

你可能感兴趣的:(Linux网络编程)