zoukankan      html  css  js  c++  java
  • read、write 与recv、send区别 gethostname

    recv相对于read有什么区别呢?

    其实它跟read函数功能一样,都可以从套接口缓冲区sockfd中取数据到buf,但是recv仅仅只能够用于套接口IO,并不能用于文件IO以及其它的IO,而read函数可以用于任何的IO;

    recv函数相比read函数多了一个flags参数,通过这个参数可以指定接收的行为,比较有用的两个选项是:

     这个这次要学习的,它可以接收缓冲区中的数据,但是并不从缓冲区中清除,这是跟read函数有区别的地方,read函数一旦读取了,就会直接从缓冲区中清除。

    readline实现

    也就是实现按行读取,读取直到 字符,实际上,它也能解决上节中提到的粘包问题,回顾下上节的粘包问题解决方案:

    包尾加 (ftp)

    我们只要解释 为止,表示前面是一个条合法的消息,对于readline的实现,可以有三种方案:

    ①、最简单的方案就是一个字符一个字符的读取,然后做判断是否有" ",但是这种效率比较低,因为会多次掉用read或recv系统函数。

    ②、用一个static变量保存接收到的数据进行缓存,在下次时从这个缓存变量中读取然后估" "判断。但是一旦用到了static变量,这意味着用到的函数是不可重录函数【关于这个概念,可以参考博文:http://www.cnblogs.com/webor2006/p/3744002.html】

    ③、偷窥的方法,也就是这次要采用的方案。下面就利用我们封装的recv_peek函数实现readline:

    server.c

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <errno.h>
    
    #define ERR_EXIT(m)
            do
            {
                    perror(m);
                    exit(EXIT_FAILURE);
            }while(0);
    
    ssize_t readn(int fd, void *buf, size_t count)//读取count个字节数,其中size_t是无符号
    的整数,ssize_t是有符号的整数
    {
        size_t nleft = count;//剩余的字节数
        printf("nleft = %d
    ",nleft);
        ssize_t nread;//已接收的字节数
        char *bufp = (char*)buf;
    
        while (nleft > 0)
        {//由于不能保证一次读操作能够返回字节数是多少,所以需要进行循环来接收
            if ((nread = read(fd, bufp, nleft)) < 0)
            {
                if (errno == EINTR)//被信号中断了,则继续执行,因为不是出错
                    continue;
                return -1;//表示读取失败了
            }
            else if (nread == 0)//对等方关闭了
                return count - nleft;//返回已经读取的字节数
    
            bufp += nread;
            nleft -= nread;
        } 
              
        return count;
    }         
             
    ssize_t writen(int fd, const void *buf, size_t count)
    {
        size_t nleft = count;
        ssize_t nwritten; 
        char *bufp = (char*)buf;
    
        while (nleft > 0) 
        {
            if ((nwritten = write(fd, bufp, nleft)) < 0)
            {
                if (errno == EINTR) 
                    continue;
                return -1;
            }
            else if (nwritten == 0)//如果是这种情况,则表示什么都没发生,继续还得执行
                    continue;
    
            bufp += nwritten;
            nleft -= nwritten;
        }
    
        return count;
    }
    
    ssize_t recv_peek(int sockfd, void *buf, size_t len)
    {
            while(1)
            {
                    int ret = recv(sockfd,buf,len,MSG_PEEK);
                    if(ret == -1 && errno == EINTR)
                            continue;
                    return ret;
            }
    }
    
    ssize_t readline(int sockfd, void *buf, size_t maxline)
    {
            int ret;
            int nread;
            char *bufp = buf;
            int nleft = maxline;
            while(1)
            {
                    ret = recv_peek(sockfd,bufp,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(sockfd,bufp,i+1);
                                    if(ret != i+1)
                                            exit(EXIT_FAILURE);
                                    return ret;
                            }
                    }
    
                    if(nread > nleft)
                            exit(EXIT_FAILURE);
                    nleft -= nread;
                    ret = readn(sockfd,bufp,nread);
                    if(ret != nread)
                            exit(EXIT_FAILURE);
                    bufp += nread;
            }
            return -1;
    }
    
    void do_service(int conn)
    {
            char recvbuf[1024];
            //struct packet recvbuf;
            int n;
            while(1)
            {
                    memset(recvbuf, 0, sizeof(recvbuf));
                    int  ret=readline(conn,recvbuf,1024);
                    if(ret == -1)
                    {
                            ERR_EXIT("readline");
                    }
                    if(ret == 0)
                    {
                            printf("client close
    ");
                            break;
                    }
    
                    fputs(recvbuf,stdout);
                    writen(conn,recvbuf,strlen(recvbuf));
            }
    }
    
    int main(void)
    {
            int listenfd;
            if((listenfd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
            {
                    ERR_EXIT("socket");
            }
            struct sockaddr_in servaddr;
            memset(&servaddr, 0, sizeof(servaddr));
            servaddr.sin_family = AF_INET;
            servaddr.sin_port = htons(5188);
            servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
            /*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/
            /*inet_aton("127.0.0.1",&servaddr.sin_addr);*/
    
            //地址重用
            int on=1;
            if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0)
            {
                    ERR_EXIT("setsockopt");
            }
    
            if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
            {
                    ERR_EXIT("bind");
            }
    
            if(listen(listenfd,SOMAXCONN) < 0)
            {
                ERR_EXIT("listen");
            }
    
            struct sockaddr_in peeraddr;
            socklen_t peerlen = sizeof(peeraddr);
            int confd;
    
            pid_t pid;
            while(1)
            {
                    if((confd = accept(listenfd,(struct sockaddr*)&peeraddr, &peerlen)) < 0)
                    {
                            ERR_EXIT("accept");
                    }
                    printf("ip = %s, port = %d
    ",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
                    pid = fork();
                    if(pid == -1)
                    {
                            ERR_EXIT("fork");
                    }
                    if(pid == 0)
                    {
                            close(listenfd);
                            do_service(confd);
                            exit(EXIT_SUCCESS);
                    }
                    else
                    {
                            close(confd);
                    }
            }
    
            return 0;
    }

    client.c

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <errno.h>
    
    #define ERR_EXIT(m)
            do
            {
                    perror(m);
                    exit(EXIT_FAILURE);
            }while(0);
    
    ssize_t readn(int fd, void *buf, size_t count)//需要将函数的定义也挪过来
    {
        size_t nleft = count;
        ssize_t nread;
        char *bufp = (char*)buf;
    
        while (nleft > 0)
        {
            if ((nread = read(fd, bufp, nleft)) < 0)
            {
                if (errno == EINTR)
                    continue;
                return -1;
            }
            else if (nread == 0)
                return count - nleft;
    
            bufp += nread;
            nleft -= nread;
        }
    
        return count;
    }
    
    ssize_t writen(int fd, const void *buf, size_t count)
    {
        size_t nleft = count;
        ssize_t nwritten;
        char *bufp = (char*)buf;
    
        while (nleft > 0)
        {
            if ((nwritten = write(fd, bufp, nleft)) < 0)
            {
                if (errno == EINTR)
                    continue;
                return -1;
            }
            else if (nwritten == 0)
                continue;
            bufp += nwritten;
            nleft -= nwritten;
        }
    
        return count;
    }
    
    ssize_t recv_peek(int sockfd, void *buf, size_t len)
    {
            while(1)
            {
                    int ret = recv(sockfd,buf,len,MSG_PEEK);
                    if(ret == -1 && errno == EINTR)
                            continue;
                    return ret;
            }
    }
    
    ssize_t readline(int sockfd, void *buf, size_t maxline)
    {
            int ret;
            int nread;
            char *bufp = buf;
            int nleft = maxline;
            while(1)
            {
                    ret = recv_peek(sockfd,bufp,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(sockfd,bufp,i+1);
                                    if(ret != i+1)
                                            exit(EXIT_FAILURE);
                                    return ret;
                            }
                    }
    
                    if(nread > nleft)
                            exit(EXIT_FAILURE);
                    nleft -= nread;
                    ret = readn(sockfd,bufp,nread);
                    if(ret != nread)
                            exit(EXIT_FAILURE);
                    bufp += nread;
            }
            return -1;
    }
    
    int main(void)
    {
            int sockfd;
            if((sockfd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
            {
                    ERR_EXIT("socket");
            }
            struct sockaddr_in servaddr;
            memset(&servaddr, 0, sizeof(servaddr));
            servaddr.sin_family = AF_INET;
            servaddr.sin_port = htons(5188);
            servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
            /*inet_aton("127.0.0.1",&servaddr.sin_addr);*/
    
            if (connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
            {
                    ERR_EXIT("connect");
            }
    
            struct sockaddr_in localaddr;
            socklen_t addrlen = sizeof(localaddr);
            if(getsockname(sockfd,(struct sockaddr*)&localaddr,&addrlen) < 0)
                    ERR_EXIT("getsockname");
            printf("ip = %s, port = %d
    ",inet_ntoa(localaddr.sin_addr),ntohs(localaddr.s
    in_port));
    
            char sendbuf[1024] = {0};
            char recvbuf[1024] = {0};
            //struct packet sendbuf;
            //struct packet recvbuf;
            //memset(&sendbuf,0,sizeof(sendbuf));
            //memset(&recvbuf,0,sizeof(recvbuf));
    
            int n;
    
            while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL)
            {
                    //writen(sockfd,sendbuf,sizeof(sendbuf));
                    //readn(sockfd,recvbuf,sizeof(recvbuf));
                    //n =strlen(sendbuf.buf);
                    //sendbuf.len = htonl(n);//网络字节序
                    writen(sockfd,sendbuf,strlen(sendbuf));
                    int ret = readline(sockfd,recvbuf,sizeof(recvbuf));
                    //int ret = readn(sockfd,&recvbuf.len,4);
                    if(ret == -1)
                    {
                            ERR_EXIT("read");
                    }
                    else if(ret == 0)
                    {
                            printf("client close
    ");
                            break;
                    }
    
                    fputs(recvbuf,stdout);
                    memset(sendbuf,0,sizeof(sendbuf));
                    memset(recvbuf,0,sizeof(recvbuf));
            }
            close(sockfd);
            return 0;
    }

    Makefile

    .PHONY: clean all
    CC=gcc
    CFLAGE= -G -Wall
    BIN=client server getiplist
    all:$(BIN)
    %.o:%.c
            $(CC) $(cflags) -C $< -O $@
    clean:
            rm -f *.o $(BIN)

    getsockname:获取套接口本地的地址

    当客户端成功与服务端连接之后,如果想知道客户端的地址,就可以通过它来获取,

    getpeername:获取对等方的地址

    由于它的使用方法跟getsockname一样,这里就不说明了,注意:sockfd需是连接成功的套接口,另外对于服务端获取客户端ip,像这种情况下也需用这个接口来获得:

     gethostname:获取主机的名称

    gethostbyname:通过主机名来获取主机上所有的ip地址

    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    
    #define ERR_EXIT(m) 
            do 
            { 
                    perror(m); 
                    exit(EXIT_FAILURE); 
            } while(0)
    
    int getlocalip(char *ip)
    {
        char host[100] = {0};
        if (gethostname(host, sizeof(host)) < 0)
          return -1;
        struct hostent *hp;
        if ((hp = gethostbyname(host)) == NULL)
          return -1;
        strcpy(ip, inet_ntoa(*(struct in_addr*)hp->h_addr_list[0]));
        return 0;
    
    }
    
    int main(void)
    {
        char host[100] = {0};
        if (gethostname(host, sizeof(host)) < 0)
            ERR_EXIT("gethostname");
    
        struct hostent *hp;
        if ((hp = gethostbyname(host)) == NULL)
            ERR_EXIT("gethostbyname");
    
        int i = 0;
        while (hp->h_addr_list[i] != NULL)
        {
            printf("%s
    ", inet_ntoa(*(struct in_addr*)hp->h_addr_list[i]));
            i++;
        }
    
        char ip[16] = {0};
        getlocalip(ip);
        printf("localip=%s
    ", ip);
        return 0;
    }
  • 相关阅读:
    笔记:Struts2 的 JSON 插件
    笔记:Struts2 拦截器
    笔记:Struts2 文件上传和下载
    笔记:Struts2 文件上传和下载
    【学习总结】推荐系统-协同过滤原理
    【刷题】牛客网看到的鹅厂ML面筋-部分问题RecSys相关
    【刷题】【LeetCode】000-十大经典排序算法
    【刷题】【LeetCode】总
    【问题解决方案】pygame生成的窗口点右上角关闭按钮未响应问题的解决
    【刷题】若串 =’software’ ,其子串数目为:37
  • 原文地址:https://www.cnblogs.com/Malphite/p/11645067.html
Copyright © 2011-2022 走看看