1. 程式人生 > 其它 >用epoll()實現併發伺服器通訊

用epoll()實現併發伺服器通訊

伺服器端程式碼

#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/epoll.h>

int main(){

    //建立socket
    int lfd = socket(PF_INET,SOCK_STREAM,0);
    struct sockaddr_in saddr;
    saddr.sin_port = htons(9999);
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = INADDR_ANY;

    //繫結
    bind(lfd,(struct sockaddr*)&saddr,sizeof(saddr));

    //監聽
    listen(lfd,8);

    //呼叫epoll_creat()建立一個epoll例項
    int epfd = epoll_create(100);

    //將監聽的檔案描述符新增到epoll例項的rbr中
    struct epoll_event epev;
    epev.events = EPOLLIN;
    epev.data.fd = lfd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&epev);

    struct epoll_event epevs[1024];

    while(1){
        int ret = epoll_wait(epfd,epevs,1024,-1);
        if(ret == -1){
            perror("epoll_wait");
            exit(-1);
        }
        // printf("ret = %d\n",ret);//將客戶端中sleep(1)改為usleep(1000)可以看到ret = 2
        for(int i = 0; i < ret; i++){
            if(epevs[i].data.fd == lfd){
                //監聽的檔案描述符,有客戶端連線
                struct sockaddr_in caddr;
                int len = sizeof(caddr);
                int cfd = accept(lfd,(struct sockaddr*)&caddr,&len);
                
                printf("有新客戶端連線,IP : %d,port : %d\n",caddr.sin_addr.s_addr,caddr.sin_port);

                epev.events = EPOLLIN;//epev.events = EPOLLIN | EPOLLOUT
                epev.data.fd = cfd;
                epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&epev);
            }else{
                if(epevs[i].events & EPOLLOUT){//檢測的有寫入資料
                    continue;
                }
                //檢測到有讀資料到達,需要通訊
                char buf[1024] = {0};
                int len = read(epevs[i].data.fd,buf,sizeof(buf));
                if(len == -1){
                    perror("read");
                    exit(-1);
                }else if(len == 0){
                    printf("client closed...");
                    close(epevs[i].data.fd);
                    epoll_ctl(epfd,EPOLL_CTL_DEL,epevs[i].data.fd,NULL);
                }else if(len > 0){
                    printf("read buf: %s\n",buf);
                    write(epevs[i].data.fd,buf,strlen(buf)+1);
                }
            }
        }
    }
    close(lfd);
    close(epfd);
    return 0;
}

客戶端程式碼

//客戶端
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main(){

    //建立套接字
    int fd = socket(AF_INET,SOCK_STREAM,0);
    if(fd == -1){
        perror("socket");
        exit(-1);
    }

    //連線伺服器
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    inet_pton(AF_INET,"192.168.245.128",&saddr.sin_addr.s_addr);
    saddr.sin_port = htons(9999);
    int ret = connect(fd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(ret == -1){
        perror("connect");
        exit(-1);
    }

    //通訊
    char recvBuf[1024] = {0};
    int i = 0;
    while(1){
        sprintf(recvBuf,"data : %d\n",i++);
        write(fd,recvBuf,strlen(recvBuf));

        int len = read(fd,recvBuf,sizeof(recvBuf));
        if(len == -1){
            perror("read");
            exit(-1);
        }else if(len > 0){
            printf("recv server data : %s\n",recvBuf);
        }else if(len == 0){
            printf("server closed...");
            break;
        }
        //sleep(1);
        usleep(1000);
    }
    return 0;
}

執行效果圖