【Linux编程】用select处理普通数据和带外数据
2015-12-06 21:07
447 查看
传输层的TCP协议有带外数据的概念,带外数据又称为紧急数据,它比普通数据有更高的优先级,一般会立即发送,而不会排队等待。
在TCP协议头部结构中有URG标志位和16位的紧急指针,若URG标志位被设置,表示紧急指针有效,此时紧急指针将指向紧急数据的下一个字节。
带外数据只有一个字节大小,因为服务器将读取到的带外数据存入一个特殊的缓冲区,这个缓冲区只有一个字节的大小,并且带外数据会将TCP字节流截断,可以用带MSG_OOB标志的recv系统调用来读取带外数据,
在网络编程中,select能监听可读,可写和异常事件,但能监听的异常事件只有一种,那就是socket上接收到带外数据。socket上接收到普通数据和带外数据都将使select返回,但前者处于可读状态,后者处于异常状态。
用select处理普通数据和带外数据的代码如下:
在TCP协议头部结构中有URG标志位和16位的紧急指针,若URG标志位被设置,表示紧急指针有效,此时紧急指针将指向紧急数据的下一个字节。
带外数据只有一个字节大小,因为服务器将读取到的带外数据存入一个特殊的缓冲区,这个缓冲区只有一个字节的大小,并且带外数据会将TCP字节流截断,可以用带MSG_OOB标志的recv系统调用来读取带外数据,
在网络编程中,select能监听可读,可写和异常事件,但能监听的异常事件只有一种,那就是socket上接收到带外数据。socket上接收到普通数据和带外数据都将使select返回,但前者处于可读状态,后者处于异常状态。
用select处理普通数据和带外数据的代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/select.h> int main(int argc, char *argv[]){ if(argc!=3) printf("格式:%s <IP地址> <端口号>\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 socket 初步
- linux lsof详解
- linux 文件权限
- Linux 执行数学运算
- 10 篇对初学者和专家都有用的 Linux 命令教程
- Linux 与 Windows 对UNICODE 的处理方式
- Ubuntu12.04下QQ完美走起啊!走起啊!有木有啊!
- 解決Linux下Android开发真机调试设备不被识别问题
- 运维入门
- 运维提升
- Linux 自检和 SystemTap
- Ubuntu Linux使用体验
- c语言实现hashmap(转载)
- Linux 信号signal处理机制
- linux下mysql添加用户
- Scientific Linux 5.5 图形安装教程
- 基于 Linux 集群环境上 GPFS 的问题诊断
- 谁是桌面王者?Win PK Linux三大镇山之宝
- vivi下重新调整分区