zoukankan      html  css  js  c++  java
  • TCP之简单回传(四)

    继续采用 TCP之简单回传(三) 的思路,不过由于其转型时,每次读取一个字符都要调用系统函数一次,故其效率较低;

    本次我们采用系统中一个函数recv实现预读取

    int PASCAL FAR recv( SOCKET s, char FAR* buf, int len, int flags);
    s:一个标识已连接套接口的描述字。
    buf:用于接收数据的缓冲区。
    len:缓冲区长度。
    flags:指定调用方式。
    MSG_PEEK 查看当前数据。数据将被复制到缓冲区中,但并不从输入队列中删除。

    通过预览内核缓冲区中的数据判断,我们所预览的数据中是否存在' ';
    若存在,则将 ' '之前的数据(包括' ')读进我们自己的缓冲区;

    若不存在,则直接将我们预览的所有数据读进缓冲区;

    recv_peek 以及readn解决这个问题;

    代码如下:

    //预览内核缓冲区数据
    ssize_t recv_peek(int fd, void *usrbuf, size_t maxlen)
    {
        ssize_t nread;
        do
        {
            nread = recv(fd, usrbuf, maxlen, MSG_PEEK);        
        } 
        while(nread == -1 && errno == EINTR);
        return nread;
    }
    
    ssize_t readline(int fd, void *usrbuf, size_t maxlen)
    {
        char *bufp = (char *)usrbuf;
        size_t nleft = maxlen - 1;
        ssize_t count = 0;
    
        ssize_t  nread;
        while(nleft > 0)
        {
            nread = recv_peek(fd, bufp, nleft);//预览内核缓冲区数据
            if( nread <= 0)  //由客户端处理
                return nread;
            //遍历bufp,以确定是否存在
     
            int i;
            for ( i = 0; i < nread; i++) 
            {
            //存在'
    '    
                if(bufp[i] == '
    ')
                {
                    size_t nsize = i +1; 
                    if( readn(fd, bufp, nsize) != nsize)//说明
    前有i个字符
                        ERR_EXIT("readn");
                    bufp +=nsize; //重置偏移量
                    count +=nsize;//统计读取个数
                    *bufp = 0;
                    return count;
                }
            }
            //不存在'
    '
            if( readn(fd, bufp, nread) != nread)
                ERR_EXIT("readn");
            bufp += nread;
            count += nread;
            nleft -=nread;
        }
        *bufp = 0;
        return count;
    }
    View Code

    server服务器代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #define ERR_EXIT(m) 
        do { 
            perror(m);
            exit(EXIT_FAILURE);
        }while(0)
    
    void do_server(int fd);
    
    int main(int argc, const char *argv[])
    {
    //socket    
        int listenfd = socket(AF_INET, SOCK_STREAM, 0 );
        if( -1 == listenfd)
            ERR_EXIT("socket");
    //地址复用
        int on = 1;
        if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) < 0)
            ERR_EXIT("setsockopt");
    //bind
        struct sockaddr_in addr;
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(8888); //主机字节序转化为网络字节序
        addr.sin_addr.s_addr = inet_addr("127.0.0.1");//点分十进制转化成网络字节序
        if( -1 == bind( listenfd, (struct sockaddr*)&addr, sizeof(addr)))
            ERR_EXIT("bind");
    
    //listen
        if( -1 == listen(listenfd,SOMAXCONN ))
            ERR_EXIT("listen");
        
    //accept    
        int peerfd = accept(listenfd, NULL, NULL);//对方的IP&PORT
    
    //read&write    
        do_server(peerfd);
    
    //close
        close(peerfd);
        close(listenfd);
        return 0;
    }
    
    void do_server(int  fd)
    {
        char recvbuf[1024100] = {0};
        int cnt =0;
        while(1)
        {
            int nread = readline(fd, recvbuf, sizeof(recvbuf));
            if(nread == -1)//err
            {
                if(errno == EINTR)
                    continue;
                ERR_EXIT("read");
            }else if (nread == 0 )//write close
            {
                printf("close...
    ");
                exit(EXIT_FAILURE);
            }
            
            // ok 
            printf("count = %d recv size = %d
    ",++cnt, nread);
            memset(recvbuf, 0, sizeof(recvbuf));
        }
    }
    View Code

    client客户端代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #define ERR_EXIT(m) 
        do { 
            perror(m);
            exit(EXIT_FAILURE);
        }while(0)
    void do_server(int fd);
    
    int main(int argc, const char *argv[])
    {
    //socket
        int peerfd = socket(AF_INET, SOCK_STREAM,0);
        if( -1 == peerfd)
            ERR_EXIT("socket");
    //connect
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(8888);
        addr.sin_addr.s_addr = inet_addr("127.0.0.1");
        
        if( -1 == connect(peerfd,(struct sockaddr*)&addr, sizeof(addr) ))
            ERR_EXIT("connect");
    
    //read&write
        do_server(peerfd);
    
        return 0;
    }
    
    void do_server(int fd)
    {
        #define SIZE 1024
        char sendbuf[SIZE +1]= {0};
        int i ;
        for (i = 0; i < SIZE-1; i++) //attention
        {
            sendbuf[i]= 'a';    
        }
        sendbuf[SIZE-1] = '
    ';//标志位
        int cnt =0;
        while(1)
        {
            int i;
            for (i = 0; i < 10; i++) 
            {
                int nwrite =writen(fd, sendbuf, SIZE);//发送SIZE个数据中最后一个字符为
    
                if( nwrite != SIZE)
                    ERR_EXIT("writen");
                printf("cout = %d,write %d bytes
    ",++cnt, SIZE);
            }
            nano_sleep(4.5);
        }
    }
    View Code

    测试结果:

    ./server
    count = 1 recv size = 1024
    count = 2 recv size = 1024
    count = 3 recv size = 1024
    count = 4 recv size = 1024
    count = 5 recv size = 1024
    count = 6 recv size = 1024
    count = 7 recv size = 1024
    count = 8 recv size = 1024
    count = 9 recv size = 1024
    count = 10 recv size = 1024
    count = 11 recv size = 1024
    count = 12 recv size = 1024
    count = 13 recv size = 1024
    count = 14 recv size = 1024
    count = 15 recv size = 1024
    count = 16 recv size = 1024
    count = 17 recv size = 1024
    count = 18 recv size = 1024
    count = 19 recv size = 1024
    count = 20 recv size = 1024
    View Code
    ./client
    count = 1 recv size = 1024
    count = 2 recv size = 1024
    count = 3 recv size = 1024
    count = 4 recv size = 1024
    count = 5 recv size = 1024
    count = 6 recv size = 1024
    count = 7 recv size = 1024
    count = 8 recv size = 1024
    count = 9 recv size = 1024
    count = 10 recv size = 1024
    count = 11 recv size = 1024
    count = 12 recv size = 1024
    count = 13 recv size = 1024
    count = 14 recv size = 1024
    count = 15 recv size = 1024
    count = 16 recv size = 1024
    count = 17 recv size = 1024
    count = 18 recv size = 1024
    count = 19 recv size = 1024
    count = 20 recv size = 1024
    View Code
  • 相关阅读:
    11
    消除左递归
    4.K均值算法--应用
    3.K均值算法
    2.机器学习相关数学基础作业
    机器算法学习第一次作业
    第十五次作业
    第十四次作业
    第十三次作业
    第十二次作业
  • 原文地址:https://www.cnblogs.com/xfxu/p/4027624.html
Copyright © 2011-2022 走看看