UNIX(网络编程-IO操作):16---非阻塞读写案例

一、案例简介

二、程序源码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/socket.h>
#include<sys/select.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/time.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>

#define MAXLINE 1024
int max(int f1,int f2);
void str_cli(FILE *fp,int sockfd);
char *gf_time(void);

int main(int argc,char *argv[])
{
    if(argc!=3){
        perror("please enter [IP] [PORT]");
        exit(EXIT_FAILURE);
    }

    int sockFd=socket(AF_INET,SOCK_STREAM,0);
    if(sockFd<0){
        perror("socket");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in serverAddr;
    serverAddr.sin_family=AF_INET;
    serverAddr.sin_port=htons(atoi(argv[2]));
    if((inet_aton(argv[1],(struct in_addr*)&serverAddr.sin_addr))==0){
        perror("inet_aton");
        exit(EXIT_FAILURE);
    }

    if(connect(sockFd,(struct sockaddr*)&serverAddr,sizeof(serverAddr))<0){
        printf("Connect failed,reasons:%s\n",strerror(errno));
        close(sockFd);
        exit(EXIT_FAILURE);
    }
 
    printf("Connect success\n");

    str_cli(stdin,sockFd);

    exit(0);
}

void str_cli(FILE *fp,int sockfd)
{
    int maxfdp1,val,stdineof,retval;
    ssize_t n,nwritten;
    fd_set rset,wset;
    char to[MAXLINE],fr[MAXLINE]; //to存放标准输入,fr存放标准输出
    char *toiptr,*tooptr,*friptr,*froptr;

    val=fcntl(sockfd,F_GETFL,0);
    fcntl(sockfd,F_SETFL,val | O_NONBLOCK);//把sockfd设为非阻塞

    val=fcntl(STDIN_FILENO,F_GETFL,0);
    fcntl(STDIN_FILENO,F_SETFL,val | O_NONBLOCK);//把标准输入设为非阻塞

    val=fcntl(STDOUT_FILENO,F_GETFL,0);
    fcntl(STDOUT_FILENO,F_SETFL,val | O_NONBLOCK);//把标准输出设为非阻塞

    toiptr=tooptr=to;
    friptr=froptr=fr;
    stdineof=0;

    maxfdp1=max(max(STDIN_FILENO,STDOUT_FILENO),sockfd)+1;
    for(;;){
        FD_ZERO(&rset);
        FD_ZERO(&wset);
        if(stdineof==0 && toiptr<&to[MAXLINE])//如果标准输入还可以存放数据
            FD_SET(STDIN_FILENO,&rset);
        if(friptr<&fr[MAXLINE])
            FD_SET(sockfd,&rset);
        if(tooptr!=toiptr)
            FD_SET(sockfd,&wset);
        if(froptr!=friptr)
            FD_SET(STDOUT_FILENO,&wset);
        switch(retval=select(maxfdp1,&rset,&wset,NULL,NULL))
        {
            case -1:
                perror("select");
                continue;
            case 0:
                printf("timeout\n");
                continue;
            default:
                if(FD_ISSET(STDIN_FILENO,&rset))//从标准输入读取数据
                {
                    if((n=read(STDIN_FILENO,toiptr,&to[MAXLINE]-toiptr))<0){
                        if(errno!=EWOULDBLOCK)
                            perror("read error on stdin");
                    }else if(n==0){
                        fprintf(stderr,"%s:EOF on stdin\n",gf_time());
                        stdineof=-1;
                        if(tooptr==toiptr)//关闭写端
                            shutdown(sockfd,SHUT_WR);
                    }else{
                        fprintf(stderr,"%s:read %d bytes from stdin\n",gf_time(),n);
                        toiptr+=n;
                        FD_SET(sockfd,&wset);
                    }
                }

                if(FD_ISSET(sockfd,&rset))
                {
                    if((n=read(sockfd,friptr,&fr[MAXLINE]-friptr))<0){
                        if(errno!=EWOULDBLOCK)
                            perror("read error on socket");
                    }else if(n==0){
                        fprintf(stderr,"%s:EOF on socket\n",gf_time());
                        if(stdineof)
                            return;
                        else
                            perror("str_cli:server terinated prematurely");
                    }else{
                        fprintf(stderr,"%s:read %d bytes from socket\n",gf_time(),n);
                        friptr+=n;
                        FD_SET(STDOUT_FILENO,&wset);
                    }
                }

                if(FD_ISSET(STDOUT_FILENO,&wset)&&((n=friptr-froptr)>0))
                {
                    if((nwritten=write(STDOUT_FILENO,froptr,n))<0){
                        if(errno!=EWOULDBLOCK)
                            perror("write error to stdout");
                    }else{
                        fprintf(stderr,"%s:wrote %d bytes to stdout\n",gf_time(),nwritten);
                        froptr+=nwritten;
                        if(froptr==friptr)
                            froptr=friptr=fr;
                    }
                }

                if(FD_ISSET(sockfd,&wset)&&((n=toiptr-tooptr)>0))
                {
                    if((nwritten=write(sockfd,tooptr,n))<0){
                        if(errno!=EWOULDBLOCK)
                            perror("write error to socket");
                    }else{
                        fprintf(stderr,"%s:wrote %d bytes to socket\n",gf_time(),nwritten);
                        froptr+=nwritten;
                        if(tooptr==toiptr)
                            toiptr=tooptr=to;
                        if(stdineof)
                            shutdozwn(sockfd,SHUT_WR);
                    }
                }
                break;
        }
        
    }
}

int max(int f1,int f2)
{
    if(f1>f2)
        return f1;
    else if(f1<f2)
        return f2;
    else
        return f1;
}

char *gf_time(void)
{
    struct timeval tv;
    static char str[30];
    char *ptr;
    if(gettimeofday(&tv,NULL)<0)
        perror("gettimeofday");
    ptr=ctime(&tv.tv_sec);
    strcpy(str,&ptr[11]);
    snprintf(str+8,sizeof(str)-8,

".%06ld",tv.tv_usec);
    return (str);
}

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/89857417