• TCP之简单回传(三)


    鉴于TCP之简单回传(一)   中所出现的问题,本博文所要采取的一种方法是:

    服务器端和客户端共同遵守如下约定:
    接收的字节流中,若遇到'
    ',表示一次传送完毕。

    具体为:

    客户端把每次欲发送的数据的最后一个字符设置为 ' ';

    而服务器每次接收时,一个一个字符的从缓冲区中取出一个字符,然后再判断该字符是否为' ',若不是,则继续读取;若是,则退出循环,表示本次接收结束;

    实现代码如下:

    //按字符读取--->由于每读取一个字符就产生一次系统调用,故效率较低
    ssize_t readline_slow(int fd, void *usrbuf, size_t maxlen)
    {
        char *bufp = (char*)usrbuf;//偏移位置
        ssize_t nread;
        size_t nleft = maxlen -1 ;//剩余字节数
        char ch;//保存每次读取的字符
        while( nleft > 0)//只要还有没读的,就一直循环
        {
            if(-1 == (nread=read(fd, &ch, 1)))//把从fd中读取的字符存进ch中
            {
                if(errno == EINTR)//被中断信号打断
                    continue;
                return -1;//err
            }else if(0 == nread )
                break; //EOF
            
            *bufp = ch;//将读取的字符存进buf
            bufp++;//向前移动
            
            nleft --;//剩余字节数--
            if(ch == '
    ')//如果该字符为
    。本次读取完成
                break;
        }
        *bufp ='';//
        return (maxlen- nleft -1);//最大长度 -剩余的字符 - ''
    }
    View Code

    本程序中所用到的函数都可以在 TCP之函数封装 中找到;

    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_slow(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

    注意:本程序效率比较低下,原因在于:

    每次读取一个字符都要系统调用一次read函数。

    解决方法:TCP之简单回传(四)

  • 相关阅读:
    python 判断矩阵中每行非零个数的方法
    用Python 绘制分布(折线)图
    统计numpy数组中每个值出现的个数
    pandas 获取不符合条件的dataframe
    Python 中如何判断 list 中是否包含某个元素
    docker与Spring boot的集成:docker-maven-plugin使用
    处理kdevtmpfsi挖矿病毒
    使用docker-maven-plugin推送镜像到远程docker服务器
    docker 开启2375端口,提供外部访问docker
    Spring Boot 配置优先级顺序
  • 原文地址:https://www.cnblogs.com/xfxu/p/4027555.html
Copyright © 2020-2023  润新知