利用程序池給客戶端傳檔案

Eaven_Wang發表於2024-06-04

主函式

#include <func.h>
#include "process_pool.h"
#include "server.h"
#include "transferFd.h"
#define EVENTSNUM 100

int main(int argc,char* argv[]){
    //ip port processNum
    if(argc != 4){
        error(1,errno,"need three arguments");
    }

    char* ip = argv[1];
    int port = atoi(argv[2]);
    int processNum = atoi(argv[3]);
    process_pool* pProcess = (process_pool*)calloc(processNum,sizeof(process_pool));

    makeChildren(pProcess,processNum);

    int listenfd = serverCreate(ip,port);
    if(listenfd == -1){
        perror("serverCreate");
    }

    int epfd = epoll_create1(0);
    listenAdd(epfd,listenfd);
    for(int i = 0;i < processNum;i++){
        listenAdd(epfd,pProcess[i].peerfd);
    }
    struct epoll_event events[EVENTSNUM]; 

    while(1){
        int nReady = epoll_wait(epfd,events,EVENTSNUM,-1);

        for(int i = 0;i < nReady;i++){
            int fd = events[i].data.fd;

            if(fd == listenfd){
                int peerfd = accept(listenfd,NULL,NULL);
                if(peerfd == -1){
                    perror("accept");
                }
                printf("connection\n");
                for(int j = 0;j < processNum;j++){
                    if(pProcess[j].processStatus == FREE){
                         sendFd(pProcess[j].peerfd,peerfd);
                         pProcess[j].processStatus = BUSY;
                         break;
                    }
                }
                close(peerfd);
            }else{
                char buffer[1024];
                memset(buffer,0,sizeof(buffer));
                read(fd,buffer,sizeof(buffer));
                for(int j = 0;j < processNum;j++){
                    if(pProcess[j].peerfd == fd){
                            pProcess[j].processStatus = FREE;
                            break;
                    }
                }

            }
        }
    }
    close(listenfd);
    return 0;
}

process_pool

#include <func.h>
#include "process_pool.h"
#include <sys/uio.h>
#include "transferFd.h"
#include "server.h"

int handleTask(int pipeFd){
    printf("child handle task\n");
    while(1){
        int clientFd;
        char fileName[] = "hello.txt";
        recvFd(pipeFd,&clientFd);

        printf("clientFd : %d\n",clientFd);
        sendFile(clientFd,fileName);
        close(clientFd);
        int OK = 1;
        write(pipeFd,&OK,sizeof(OK));
    }
    
    return 0;
}



int makeChildren(process_pool* pProcess,int processNum){
    printf("processNum : %d\n",processNum);
    for(int i = 0;i < processNum;i++){
        
        int pipe[2];
        socketpair(AF_LOCAL,SOCK_STREAM,0,pipe);
        pid_t pid = fork();
        if(pid == 0){
            close(pipe[1]);
            handleTask(pipe[0]);
            exit(0);
        }
        close(pipe[0]);
        printf("chile %d\n",pid);
        pProcess[i].pid = pid;
        pProcess[i].processStatus = FREE;
        pProcess[i].peerfd = pipe[1];
        
    }
    return 0;
}

server

#include "server.h"
#include <func.h>
int serverCreate(char*ip,int port){
    int sfd = socket(AF_INET,SOCK_STREAM,0);
    if(sfd == -1){
        perror("socket");
    }

    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = inet_addr(ip);
    serverAddr.sin_port = htons(port);
    int on = 1;
    setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

    int ret = bind(sfd,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
    if(ret == -1){
        perror("bind");
    }
    ret = listen(sfd,10);
    if(ret == -1){
        perror("listen");
    }
    return sfd;
}

int listenAdd(int epfd,int fd){
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = EPOLLIN;
    int ret = epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev);
    if(ret == -1){
        perror("epoll_ctl");
    }
    return 0;
}

int listenDel(int epfd,int fd){
    int ret = epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);
    if(ret == -1){
        perror("epoll_ctl");
    }
    return 0;
}

int sendFile(int clientFd,char* fileName){
    fileInfo file;
    file.len = strlen(fileName);

    strcpy(file.fileContent,fileName);    
    send(clientFd,&file,4 + file.len,0);
    printf("fileName: %s\n",file.fileContent);

    int fd = open(fileName,O_RDONLY);
    struct stat buf;
    int ret = fstat(fd,&buf);
    if(ret == -1){
        error(1,errno,"fstat");
    }


    file.len = buf.st_size;
    char buffer[100];
    read(fd,buffer,sizeof(buffer));
    strncpy(file.fileContent,buffer,file.len);
    send(clientFd,&file,4 + file.len,0);

    printf("fileContent: %s\n",file.fileContent);
    return 0;
}

transferFd

#include <func.h>
#include <sys/uio.h>
#include "transferFd.h"

int sendFd(int pipeFd,int fd){
     
    int len = CMSG_LEN(sizeof(fd));
    struct cmsghdr* cmsg = (struct cmsghdr*)calloc(1,len);
    cmsg->cmsg_len = len;
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    int *p = (int*)CMSG_DATA(cmsg);
    *p = fd;
    char buff[4] = {0};
    //構建第二組成員
    struct iovec iov;
    iov.iov_base = buff;
    iov.iov_len = sizeof(buff);

    struct msghdr msg;
    msg.msg_control = cmsg;
    msg.msg_controllen = len;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    sendmsg(pipeFd,&msg,0);
    printf("sendFd sucess\n");
    free(cmsg);
    return 0;
}

int recvFd(int pipeFd,int* pfd){

    int len = CMSG_LEN(sizeof(int));
    struct cmsghdr* cmsg = (struct cmsghdr*)calloc(1,len);
    cmsg->cmsg_len = len;
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;

    char buff[4] = {0};
    //構建第二組成員
    struct iovec iov;
    iov.iov_base = buff;
    iov.iov_len = sizeof(buff);

    struct msghdr msg;
    msg.msg_control = cmsg;
    msg.msg_controllen = len;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    recvmsg(pipeFd,&msg,0);
    printf("recv success\n");
    *pfd = *(int*)CMSG_DATA(cmsg);
    free(cmsg);
    return 0;
}

相關文章