《UNIX网络编程》之read_timeout实验

最近在做项目,需要做一个服务器和客户端的基于TCP的套接口网络编程,由于服务器端返回数据并不是那么的及时,因此,需要在客户端做些延迟,然后才能去读取数据,实验测试结果如下。

首先,我们先来看一下我们封装好的一个读延时函数:

#define ERR_EXIT(m)         do         {             perror(m);             exit(EXIT_FAILURE);         }while(0)

/**
 * read timeout - 读超时检测函数,不含读操作
 * @fd: 文件描述符
 * @wait_seconds: 等待超时秒数,如果为0标识不检测超时
 * 成功(未超时)返回0, 失败返回-1, 超时返回-1并且errno = ETIMEOUT
 */
int read_timeout(int fd, unsigned int wait_seconds)
{
    int ret;
    if(wait_seconds > 0)
    {
        fd_set read_fdset;
        struct timeval timeout;

        FD_ZERO(&read_fdset);
        FD_SET(fd, &read_fdset);

        timeout.tv_sec = wait_seconds;
        timeout.tv_usec = 0;

        do
        {
            ret = select(fd + 1, &read_fdset, NULL, NULL, &timeout);
        }while(ret < 0 && errno == EINTR);

        if(ret == 0)//fail
        {
            //time out.
            ret = -1;
            errno = ETIMEDOUT;
        }
        else if(ret == 1)//success
        {
            ret = 0;
        }
    }
    return ret;
}

下面,我们介绍如何使用该函数,伪代码如下:

int ret = read_timeout(sockfd, 15);

if(ret == 0)

{

  readnum = read(sockfd, recvbuff, sizeof(recvbuff));

}

else if(ret == -1 && errno == ETIMEDOUT)

{

//time out dealing.

}

好,现在继续看我的服务器与客户端程序:

服务器

void str_echo(int sock)
{
    ssize_t n;
    char buff[1024];

    again:
    while( (n = read(sock, buff, sizeof(buff))) > 0)
    {
        fputs(buff, stdout);
        sleep(3);//for testing client read_timeout
        write(sock, buff, n);
    }
    if(n < 0 && errno == EINTR)
    {
        goto again;
    }
    else if(n < 0)
    {
        ERR_EXIT("read");
    }
}

int main()
{
    int listenfd, connfd;
    pid_t childpid;
    socklen_t clilen;
    struct sockaddr_in servaddr, cliaddr;

    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        ERR_EXIT("socket");
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(5188);

    if((bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0)
    {
        ERR_EXIT("bind");
    }

    if( (listen(listenfd, SOMAXCONN)) < 0)
    {
        ERR_EXIT("listen");
    }

    for(;;)
    {
        clilen = sizeof(cliaddr);
        connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);
        if(connfd < 0)
        {
            ERR_EXIT("connect");
        }

        if( (childpid = fork()) == 0)
        {
            //child
            close(listenfd);
            str_echo(connfd);
            exit(0);
        }
        else
        {
            //parent
            close(connfd);
        }

    }
}

客户端

void str_cli(int sock)
{
    char sendbuff[1024];
    char recvbuff[1024];

    memset(sendbuff, 0, sizeof(sendbuff));
    memset(recvbuff, 0, sizeof(recvbuff));
    int ret = -1;

    //ssize_t n;
    while(fgets(sendbuff, sizeof(sendbuff), stdin) != NULL)
    {
        write(sock, sendbuff, strlen(sendbuff));    

        ret = read_timeout(sock, 15);
        if(ret == 0)
        {
            read(sock, recvbuff, sizeof(recvbuff));
        }
        else if(ret == -1 && errno == ETIMEDOUT)
        {
            ERR_EXIT("read_timeout");
        }
        fputs(recvbuff, stdout);
    }
}

int main(int argc, char **argv)
{

    int sockfd;
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    servaddr.sin_port = htons(5188);

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        ERR_EXIT("socket");
    }

    if( (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0)
    {
        ERR_EXIT("connect");
    }

    str_cli(sockfd);
    return 0;
}

例子一:

服务器延时3s, 客户端read_timeout(socd, 5);结果为:成功

时间: 2024-10-24 11:25:51

《UNIX网络编程》之read_timeout实验的相关文章

unix网络编程环境搭建

unix网络编程环境搭建 新建 模板 小书匠 1.点击下载源代码 可以通过下列官网中的源代码目录下载最新代码: http://www.unpbook.com/src.html 2.解压文件 tar -xzvf upv13e.tar.gz 3.上传至阿里云 本人本地已经配置好,这次实验是将环境搭建至云服务器中. scp -r unpv13e [email protected]120.76.140.119:/root/program/unp // -r 上传文件夹  4.编译文件 cd unpv13

【LINUX/UNIX网络编程】之简单多线程服务器(多人群聊系统)

RT,Linux下使用c实现的多线程服务器.这个真是简单的不能再简单的了,有写的不好的地方,还希望大神轻拍.(>﹏<) 本学期Linux.unix网络编程的第四个作业. 先上实验要求: [实验目的] 1.熟练掌握线程的创建与终止方法: 2.熟练掌握线程间通信同步方法: 3.应用套接字函数完成多线程服务器,实现服务器与客户端的信息交互. [实验内容] 通过一个服务器实现最多5个客户之间的信息群发. 服务器显示客户的登录与退出: 客户连接后首先发送客户名称,之后发送群聊信息: 客户输入bye代表退

UNIX网络编程 卷1:套接字联网API

这篇是计算机类的优质预售推荐>>>><UNIX网络编程 卷1:套接字联网API> UNIX和网络专家W. Richard Stevens的传世之作,世界著名网络专家Bill Fenner和Andrew M. Rudoff执笔新版 编辑推荐 这是一部传世之作!顶级网络编程专家Bill Fenner和Andrew M. Rudoff应邀执笔,对W. Richard Stevens的经典作品进行修订.书中吸纳了近几年网络技术的发展,增添了IPv6.SCTP协议和密钥管理套接字

UNIX网络编程卷1 回射客户程序 TCP客户程序设计范式

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 下面我会介绍同一个使用 TCP 协议的客户端程序的几个不同版本,分别是停等版本.select 加阻塞式 I/O 版本. 非阻塞式 I/O 版本.fork 版本.线程化版本.它们都由同一个 main 函数调用来实现同一个功能,即回射程序客户端. 它从标准输入读入一行文本,写到服务器上,读取服务器对该行的回射,并把回射行写到标准输出上. 其中,非阻塞式 I/O 版本是所有版本中执行速度最快的,

Unix网络编程中的五种I/O模型_转

转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描述符.接受数据缓冲地址.大小传递给内核,但是如果此时 该与该套接口相应的缓冲区没有数据,这个时候就recvfrom就会卡(阻塞)在这里,知道数据到来的时候,再把数据拷贝到应用层,也就是传进来的地址空 间,如果没有数据到来,就会使该函数阻塞在那里,这就叫做阻塞I/O模型,如下图: 2. 非阻塞I/O模

unix网络编程代码(2)

继续贴<unix网络编程>上的示例代码.这次是一个反射程序,反射是客户端讲用户输入的文本发送到服务器端,服务器端读取客户端发过来的文本消息,然后原封不动的把文本消息返回给客户端.使用tcp协议连接客户端和服务端,我已经在我的阿里云服务器上测试过了,能够完美运行. 首先是头文件wrap.h,在该头文件中,声明了封装部分网络编程套接字api的包裹函数,以及某些宏定义. 1 #ifndef WRAP_H_ 2 #define WRAP_H_ 3 4 #include <stdio.h>

Unix网络编程 之 socket基础

基本结构 (这部分的地址均为网络地址<网络字节序>) 1.struct sockaddr:通用套接字地址结构 此结构用于存储通用套接字地址. 数据结构定义: typedef unsigned short sa_family_t; struct sockaddr { sa_family_t sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ };    sa_fa

Unix网络编程之基本TCP套接字编程(上)

TCP客户/服务器实例 服务器程序 #include "unp.h" int main(int argc, char **argv) { int listenfd, connfd; pid_t childpid; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; listenfd = Socket(AF_INET, SOCK_STREAM, 0); //1 bzero(&servaddr, sizeof(servad

【UNIX网络编程】FIFO

管道作为进程间通信的最古老方式,它的缺点是没有名字,因此只能用在有亲缘关系的父子进程之间.对于无亲缘关系的进程间,无法用管道进行通信.FIFO可以完成无亲缘关系的进程间的通信,FIFO也被称为命名管道.它是一种特殊类型的文件,在文件系统中以文件名的形式存在,但它的行为却和上面提到的管道类似. 创建命名管道有两种方法: 1.在命令行上执行命令:mkfifo filename 来创建FIFO. 2.使用mkfifo函数创建FIFO. #include <sys/stat.h> #include &

【UNIX网络编程】进程间通信之管道

管道是最早的Unix进程间通信形式,它存在于全部的Unix实现中.关于管道,有例如以下几点须要知道: 1.它是半双工的,即数据仅仅能在一个方向上流动.虽然在某些Unix实现中管道能够是全双工的.但须要对系统进行某些设置.在Linux系统中,它是半双工的. 2.它没有名字.因此仅仅能在具有公共祖先的进程之间使用. 通经常使用在父子进程间.虽然这一点随着"有名管道FIFO"的增加得到改正了.但应该把它们看作是两种不同的进程间通信方式. 3.它由pipe函数创建,read和write函数訪问