zoukankan      html  css  js  c++  java
  • 粘包

    粘包及处理方法

    粘包:由于缓冲区及下层硬件的原因,第n个包与第n+1个包合并在一起发送,或第n个包与第n+1个包的一部分合并在一起发送,等等。如果接收方要求格式良好,那我们就必须控制发送与接收方式。
    处理方法:
    1.发送定长包,发送方每次固定发送n个字节长,同时接受方固定每次读n个字节长。缺点:数据不长时,浪费宽带和低效率。
    2.发送包头+包体,先发送定长的n字节包头(用于表示数据长度),再发送由包头中所指定长度的数据
    3.以行(' ')为单位进行读取

    定长包

    在2.5版添加如下函数,然后在main函数中将read/write修改为readn和writen即可

    ssize_t readn(int fd,void *buff,size_t count){
        char *buffp;
        ssize_t nread;
        size_t nleft;
     
        buffp=(char *)buff;
        nleft=count;
        while(nleft > 0){
            if((nread = read(fd,buffp,nleft)) < 0){
                if(errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nread == 0)
                break;
            nleft -= nread;
            buffp += nread;
        }
        return count-nleft;
    }
     
    ssize_t writen(int fd,const void *buff,size_t n){
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;
     
        ptr=buff;
        nleft=n;
        while(nleft > 0){
            if((nwritten=write(fd,ptr,nleft)) < 0){
                if(nwritten < 0 && errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nwritten == 0)
                break;
            nleft -= nwritten;
            ptr += nwritten;
        }
        return n-nleft;
    }
    

    包头+包体

    注意点:包头中定义包体的长度的int需要以网络字节序来记录, 所以在发送时要用htonl,在接收时要用ntohl
    server.c

    #include <unistd.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <signal.h>
    #include <sys/wait.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
     
    void err_quit(const char *s){
        perror(s);
        exit(1);
    }
     
    void handler(int signo){
        printf("program terminated
    ");
        exit(0);
    }
     
    struct packet{
        int len;
        char buf[1024];
    };
     
    ssize_t readn(int fd,void *buff,size_t count){
        char *buffp;
        ssize_t nread;
        size_t nleft;
     
        buffp=(char *)buff;
        nleft=count;
        while(nleft > 0){
            if((nread = read(fd,buffp,nleft)) < 0){
                if(errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nread == 0)
                break;
            nleft -= nread;
            buffp += nread;
        }
        return count-nleft;
    }
     
    ssize_t writen(int fd,const void *buff,size_t n){
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;
     
        ptr=buff;
        nleft=n;
        while(nleft > 0){
            if((nwritten=write(fd,ptr,nleft)) < 0){
                if(nwritten < 0 && errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nwritten == 0)
                break;
            nleft -= nwritten;
            ptr += nwritten;
        }
        return n-nleft;
    }
     
    int main(int argc,char *argv[]){
        int sockfd,connfd;
        pid_t child;
        socklen_t len;
        struct sockaddr_in addr,client;
     
        if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
            err_quit("sockfd");
     
        bzero(&addr,sizeof(addr));
        addr.sin_family=AF_INET;
        addr.sin_addr.s_addr=htonl(INADDR_ANY);
        addr.sin_port=htons(5566);
     
        int on=1;
        if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) <0)
            err_quit("setsockopt");
     
        if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr))<0)
            err_quit("bind");
     
        if(listen(sockfd,10)<0)
            err_quit("listen");
     
        len=sizeof(client);
        connfd=accept(sockfd,(struct sockaddr *)&client,&len);
        if(connfd < 0)
            err_quit("accept");
     
        struct packet pac;
        bzero(&pac,sizeof(pac));
        int n;
     
        if((child=fork())<0){
            err_quit("fork");
        }else if(child  == 0){
            while(1){
                int ret=readn(connfd,&pac.len,4);
                if(ret == -1)
                    err_quit("read");
                else if(ret < 4){
                    printf("peer closed
    ");
                    break;
                }
     
                n=ntohl(pac.len);
                ret=readn(connfd,pac.buf,n);
                if(ret < 1){
                    err_quit("read");
                }
                if(ret < n){
                    printf("peer closed
    ");
                    break;
                }
     
                fputs(pac.buf,stdout);
                bzero(&pac,sizeof(pac));
            }
            kill(getppid(),SIGUSR1);
        }else{
            signal(SIGUSR1,handler);
            while(fgets(pac.buf,sizeof(pac.buf),stdin) != NULL){
                n=strlen(pac.buf);
                pac.len=htonl(n);
                writen(connfd,&pac,n+4);
            }
        }
        exit(0);
    }
    

    client.c

    #include <unistd.h>
    #include <signal.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
     
    void err_quit(const char *s){
        perror(s);
        exit(1);
    }
     
    void handler(int signo){
        printf("program terminated
    ");
        exit(0);
    }
     
    struct packet{
        int len;
        char buf[1024];
    };
     
    ssize_t readn(int fd,void *buff,size_t count){
        size_t nleft;
        ssize_t nread;
        char *ptr;
     
        nleft=count;
        ptr=(char *)buff;
        while(nleft > 0){
            if((nread=read(fd,ptr,nleft)) < 0){
                if(errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nread == 0)
                break;
     
            ptr += nread;
            nleft -= nread;
        }
     
        return count - nleft;
    }
     
    ssize_t writen(int fd,const void *buff,size_t n){
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;
     
        nleft=n;
        while(n > 0){
            if((nwritten=write(fd,buff,nleft)) < 0){
                if(errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nwritten == 0)
                break;
     
            nleft -= nwritten;
            ptr += nwritten;
        }
     
        return n-nleft;
    }
     
    int main(int argc,char *argv[]){
        int sockfd;
        struct sockaddr_in servaddr;
        pid_t child;
     
        if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
            err_quit("socket");
     
        bzero(&servaddr,sizeof(servaddr));
        servaddr.sin_family=AF_INET;
        servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
        servaddr.sin_port=htons(5566);
     
        if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) <0)
            err_quit("connect");
     
        struct packet pac;
        bzero(&pac,sizeof(pac));
        int n;
     
        if((child=fork()) <0)
            err_quit("fork");
        else if(child == 0){
            signal(SIGUSR1,handler);
            while(fgets(pac.buf,sizeof(pac.buf),stdin) != NULL){
                n=strlen(pac.buf);
                pac.len=htonl(n);
                writen(sockfd,&pac,n+4);
            }
        }else{
            while(1){
                int ret=readn(sockfd,&pac.len,4);
                if(ret == -1)
                    err_quit("read");
                if(ret < 4){
                   printf("perr closed
    ");
                   break;
                }
     
                n=ntohl(pac.len);
                ret=readn(sockfd,pac.buf,n);
                if(ret == -1)
                    err_quit("read");
                if(ret < n){
                    printf("peer closed
    ");
                    break;
                }
                fputs(pac.buf,stdout);
                bzero(&pac,sizeof(pac));
            }
            kill(child,SIGUSR1);
        }
        exit(0);
    }
    

    行为单位进行读取

    非常适用于终端消息的性状

    server.c

    #include <unistd.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <signal.h>
    #include <sys/wait.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
     
    void err_quit(const char *s){
        perror(s);
        exit(1);
    }
     
    void handler(int signo){
        printf("program terminated
    ");
        exit(0);
    }
     
    ssize_t readn(int fd,void *buff,size_t count){
        char *buffp;
        ssize_t nread;
        size_t nleft;
     
        buffp=(char *)buff;
        nleft=count;
        while(nleft > 0){
            if((nread = read(fd,buffp,nleft)) < 0){
                if(errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nread == 0)
                break;
            nleft -= nread;
            buffp += nread;
        }
        return count-nleft;
    }
     
    ssize_t writen(int fd,const void *buff,size_t n){
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;
     
        ptr=buff;
        nleft=n;
        while(nleft > 0){
            if((nwritten=write(fd,ptr,nleft)) < 0){
                if(nwritten < 0 && errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nwritten == 0)
                break;
            nleft -= nwritten;
            ptr += nwritten;
        }
        return n-nleft;
    }
     
    ssize_t recv_peek(int fd,void *buf,size_t len){
        ssize_t ret;
        while(1){
            ret=recv(fd,buf,len,MSG_PEEK);
            if(ret == -1 && errno == EINTR)
                continue;
            return ret;
        }
    }
     
    ssize_t readline(int fd,void *buf,size_t maxline){
        ssize_t ret;
        size_t nread;
        size_t nleft;
        char *bufp;
     
        bufp=buf;
        nleft=maxline;
        while(1){
            ret=recv_peek(fd,buf,nleft);
            if(ret < 0)
                return ret;
            else if(ret == 0)
                return ret;
     
            nread=ret;
            int i;
            for(i=0;i<nread;i++){
                if(bufp[i] == '
    '){
                    ret=readn(fd,bufp,i+1);
                    if(ret != i+1)
                        err_quit("readn");
     
                    return ret;
                }
            }
     
            if(nread > nleft)
                err_quit("readn");
     
            nleft -= nread;
            ret=readn(fd,bufp,nread);
            if(ret != nread)
                err_quit("readn");
     
            bufp += nread;
        }
     
        return -1;
    }
     
    int main(int argc,char *argv[]){
        int sockfd,connfd;
        pid_t child;
        socklen_t len;
        struct sockaddr_in addr,client;
     
        if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
            err_quit("sockfd");
     
        bzero(&addr,sizeof(addr));
        addr.sin_family=AF_INET;
        addr.sin_addr.s_addr=htonl(INADDR_ANY);
        addr.sin_port=htons(5566);
     
        int on=1;
        if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) <0)
            err_quit("setsockopt");
     
        if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr))<0)
            err_quit("bind");
     
        if(listen(sockfd,10)<0)
            err_quit("listen");
     
        len=sizeof(client);
        connfd=accept(sockfd,(struct sockaddr *)&client,&len);
        if(connfd < 0)
            err_quit("accept");
     
        char buf[1024];
        bzero(buf,sizeof(buf));
     
        if((child=fork())<0){
            err_quit("fork");
        }else if(child  == 0){
            while(1){
                int ret=readline(connfd,buf,sizeof(buf));
                if(ret == -1)
                    err_quit("readline");
                else if(ret == 0){
                    printf("peer closed
    ");
                    break;
                }
     
                fputs(buf,stdout);
                bzero(buf,sizeof(buf));
            }
            kill(getppid(),SIGUSR1);
        }else{
            signal(SIGUSR1,handler);
            while(fgets(buf,sizeof(buf),stdin) != NULL){
                writen(connfd,buf,strlen(buf));
            }
        }
        exit(0);
    }
    

    client.c

    #include <unistd.h>
    #include <signal.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
     
    void err_quit(const char *s){
        perror(s);
        exit(1);
    }
     
    void handler(int signo){
        printf("program terminated
    ");
        exit(0);
    }
     
     
    ssize_t readn(int fd,void *buff,size_t count){
        size_t nleft;
        ssize_t nread;
        char *ptr;
     
        nleft=count;
        ptr=(char *)buff;
        while(nleft > 0){
            if((nread=read(fd,ptr,nleft)) < 0){
                if(errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nread == 0)
                break;
     
            ptr += nread;
            nleft -= nread;
        }
     
        return count - nleft;
    }
     
    ssize_t writen(int fd,const void *buff,size_t n){
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;
     
        nleft=n;
        while(n > 0){
            if((nwritten=write(fd,buff,nleft)) < 0){
                if(errno == EINTR)
                    continue;
                else
                    return -1;
            }else if(nwritten == 0)
                break;
     
            nleft -= nwritten;
            ptr += nwritten;
        }
     
        return n-nleft;
    }
    /* if have any data then return */
    ssize_t recv_peek(int fd,void *buf,size_t len){
        ssize_t ret;
        while(1){
            ret=recv(fd,buf,len,MSG_PEEK);
            if(ret == -1 && errno == EINTR)
                continue;
            return ret;
        }
    }
     
    ssize_t readline(int fd,void *buf,size_t maxline){
        ssize_t ret;
        size_t nread;
        size_t nleft;
        char *bufp;
     
        bufp=buf;
        nleft=maxline;
        while(1){
            ret=recv_peek(fd,buf,nleft);
            if(ret < 0)
                return ret;
            else if(ret == 0)
                return ret;
     
            nread=ret;
            int i;
            for(i=0;i<nread;i++){
                if(bufp[i] == '
    '){
                    ret=readn(fd,bufp,i+1);
                    if(ret != i+1)
                        err_quit("readn");
     
                    return ret;
                }
            }
     
            if(nread > nleft)
                err_quit("nread");
     
            nleft -= nread;
            ret=readn(fd,bufp,nread);
            if(ret != nread)
                err_quit("readn");
     
            bufp += nread;
        }
     
        return -1;
    }
     
    int main(int argc,char *argv[]){
        int sockfd;
        struct sockaddr_in servaddr;
        pid_t child;
     
        if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
            err_quit("socket");
     
        bzero(&servaddr,sizeof(servaddr));
        servaddr.sin_family=AF_INET;
        servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
        servaddr.sin_port=htons(5566);
     
        if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) <0)
            err_quit("connect");
     
        char buf[1024];
        bzero(buf,sizeof(buf));
     
        if((child=fork()) <0)
            err_quit("fork");
        else if(child == 0){
            signal(SIGUSR1,handler);
            while(fgets(buf,sizeof(buf),stdin) != NULL){
                writen(sockfd,buf,strlen(buf));
            }
        }else{
            while(1){
                int ret=readline(sockfd,buf,sizeof(buf));
                if(ret == -1)
                    err_quit("readline");
                if(ret == 0){
                    printf("peer closed
    ");
                    break;
                }
                fputs(buf,stdout);
                bzero(buf,sizeof(buf));
            }
            kill(child,SIGUSR1);
        }
        exit(0);
    }
    
  • 相关阅读:
    转载
    转载
    HDU
    HDU
    Hdu
    转载
    HDU
    UVa
    HDU
    POJ
  • 原文地址:https://www.cnblogs.com/cfans1993/p/6131900.html
Copyright © 2011-2022 走看看