写套接字io时,发现一个神奇的现象,控制台输入输出乱序
环境为ubuntu16.04

#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
int main()
{
        char buf[10]="";
        char buf2[10]="dddp\n";
        fd_set rdfds;
        struct timeval tv;
        int ret;
        FD_ZERO(&rdfds);
        FD_SET(0,&rdfds);   //文件描述符0表示stdin键盘输入
         tv.tv_sec = 3;
        tv.tv_usec = 500;
        ret = select(1,&rdfds,NULL,NULL,&tv);//第一个参数是监控句柄号+1
        if(ret<0)
              printf("selcet error\r\n");
        else if(ret == 0)
              printf("timeout \r\n");
        else
              printf("ret = %d \r\n",ret);
 
        if(FD_ISSET(0,&rdfds)){          //监控输入的确是已经发生了改变
              
               printf("reading");
              read(0,buf,4);                 //从键盘读取输入
            
         }
         write(1,buf,strlen(buf));          //在终端中回显
         printf(" %d \r\n",strlen(buf));
         return 0;
}

上面的结果输出正常顺序应该是
假如控制台输入ssss
运行结果应该为

ret=1
readingssss
4

但是实际运行结果
write/printf同时使用导致输出乱序问题1.jpg
很奇怪,更奇怪的是
如果把

printf("reading");

改成

printf("reading\n");

结果就会变成

write/printf同时使用导致输出乱序问题2.jpg

最后发现是write/printf函数的问题
write函数没有缓冲区,printf函数有缓冲区.当使用write函数时,会直接打印到控制台,
printf只有当遇到"\n"时或者程序终止时才会将缓冲区里的字符串打印出来,也可以调用fflush(stdout)强制把缓冲区输出。
或者在处理i/o之前调用setvbuf函数如:

setcbuf(stdout,0,_IONBUF,0)//这样可以使得printf立即输出不占用缓冲区
printf("aaaa");

参考链接:https://mlog.club/article/1410227