linux高性能服务器编程学习

linux-高性能服务器编程-06

测试使用readv和writev的使用

书上有服务器端的实现,自己尝试写了简单客服端的实现。
直接贴上代码

服务器端

书上的直接贴过来的
#include "head.h"

#define BUFFER_SIZE 1024

static const char* status_line[2] = {"200 OK", "500 Internal server error"};

void rwv_test_ser(const char* ip, const int &port, const char *file_name){
    int ret;
    struct sockaddr_in address;
    bzero(&address, sizeof(address));

    address.sin_family = AF_INET;
    address.sin_port = htons(port);
    inet_pton(AF_INET, ip, &address.sin_addr);

    int sockfd = socket(PF_INET, SOCK_STREAM | SOCK_CLOEXEC , 0);
    if (sockfd < 0){
        perror("sockfd");
        exit(1);
    }

    if (bind(sockfd, (struct sockaddr*)& address, sizeof(address)) < 0){
        perror("bind");
        exit(1);
    }

    if (listen(sockfd, 16) < 0){
        perror("listen");
        exit(1);
    }

    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    int acfd = accept(sockfd, (struct sockaddr*)& client_addr, &client_addr_len);
    if (acfd < 0){
        perror("acfd");
    }else {
        printf("addr:%s, port:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        // 用于保存HTTP应答的在这里插入代码片状态行、 头部字段和一个空行的缓存区
        char header_buf[BUFFER_SIZE];
        memset(header_buf, '\0', BUFFER_SIZE);
        // 用于存放目标文件内容的应用程序缓存
        char *file_buf;
        // 用于获取目标文件的属性, 比如是否为目录, 文件大小等
        struct stat file_stat;
        // 记录目标文件是否是有效文件
        bool valid = true;
        // 缓存区header_buf 目前已经使用了多少字节的空间
        int len = 0;
        if (stat(file_name, &file_stat) < 0){ // 目标文件不存在
            perror("stat");
            valid = false;
        }else {
            if (S_ISDIR(file_stat.st_mode)){ // 目标文件是一个目录
                perror("file is a dir");
                valid = false;
            }else if (file_stat.st_mode & S_IROTH){ // 当前用户有读取目标文件的权限
                /* 动态分配缓冲区 file_buf, 并指定其大小为目标文件的大小
                 * file_stat.st_size 加1, 然后讲目标文件读入缓存区file_buf中*/
                int fd = open(file_name, O_RDONLY);
                file_buf = new char[file_stat.st_size + 1];
                memset(file_buf, '\0', file_stat.st_size + 1);
                if (read(fd, file_buf, file_stat.st_size) < 0){
                    perror("read");
                    valid = false;
                }
            }
        }
        // 如果目标文件有效,则发送正常的HTTP应答
        if (valid){
            /*
             * 下面这部分内容将HTTP应答的状态行、“Content-Length” 头部字段 和一个空
             * 行一次加入head_buf中
             */
            ret = snprintf(header_buf, BUFFER_SIZE - 1, "%s %s\r\n",
                          "HTTP/1.1", status_line[0]);
            len += ret;
            ret = snprintf(header_buf + len, BUFFER_SIZE - 1 - len, "Content-Length: %d\r\n", file_stat.st_size);
            len += ret;
            ret = snprintf(header_buf + len, BUFFER_SIZE - 1 - len, "%s", "\r\n");
            /*
             * 利用writev 将header_buf 和 file_buf的内容一并写出
             */
            printf("head_buf: %s\n",header_buf);
            printf("file_buf:%s\n",file_buf);
            struct iovec iv[2];
            iv[0].iov_base = header_buf;
            iv[0].iov_len = strlen(header_buf);
            iv[1].iov_base = file_buf;
            iv[1].iov_len = file_stat.st_size;
            ret = writev(acfd, iv, 2);
            if (ret < 0){
                perror("writev:\n");
            }
        }else {
            ret = snprintf(header_buf, BUFFER_SIZE - 1, "%s %s\r\n",
                           "HTTP/1.1", status_line[1]);
            len += ret;
            ret = snprintf(header_buf + len, BUFFER_SIZE - 1 - len, "%s", "\r\n");
            send(acfd, header_buf, strlen(header_buf), 0);
        }
        close(acfd);
        delete [] file_buf;	自己随便写的,目的就是一个文件的传输.
    }
    close(sockfd) ;
}

客户端

自己随便写的,目的就是一个文件的传输.
void readv_client_test(const char *ip. const int port){
    struct sockaddr_in cli_addr;
    bzero(&cli_addr, sizeof(cli_addr));
    char *pathname = "client_test";
    int fd = open(pathname, O_RDWR | O_TRUNC | O_CREAT,0777);
    if (fd < 0){
        perror("open file:\n");
        exit(1);
    }
    int clisockfd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
    if (clisockfd < 0){
        perror("clisockfd");
        exit(1);
    }
    cli_addr.sin_family = PF_INET;
    cli_addr.sin_port = htons(port);
    inet_pton(PF_INET, ip, &cli_addr.sin_addr);
    if (connect(clisockfd, (struct sockaddr*)&cli_addr, sizeof (cli_addr)) < 0){
        perror("connect");
          exit(1);
    }
    int pipefd[2];
    int ret = pipe(pipefd);
    /*
     * 使用splice函数实现文件内容的传输,splice函数至少有一个描述符是管道描述符
     */
    ret = splice(clisockfd, NULL, pipefd[1], NULL, 32768,
                 SPLICE_F_MOVE); 
    if (ret < 0){
        perror("splice read:\n");
        exit(1);
    }
    ret = splice(pipefd[0], NULL, fd, NULL, 32768, SPLICE_F_MOVE);
    if (ret < 0){
        perror("splice write:\n");
        exit(1);
    }
    close(fd);
    close(clisockfd);
}

服务器端代码转载于:《linux高性能服务器编程》–游双

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值