epoll 分次 接收数据

这个示例展示了如何使用epoll和非阻塞I/O来创建一个高效的TCP服务器,该服务器监听8888端口并接受来自客户端的连接。客户端发送特定的数据包,服务器读取并响应。代码中包含了处理连接、读写、epoll事件等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

server.c

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <sys/ioctl.h> 

#define true                1
#define false               0
#define MAX_EVENT_NUMBER    1024
#define BUFFER_SIZE         16

typedef struct recv_cmd {
    int fd; 
    char buf[BUFFER_SIZE];
    int len;
} recv_cmd_t;

int setnonblocking(int fd) 
{
    int old_option = fcntl(fd, F_GETFL);
    int new_option = old_option | O_NONBLOCK;
    fcntl(fd, F_SETFL, new_option);
    return old_option;
}

void addfd(int epollfd, int fd, int enable_et)
{
    int ret = 0;
    struct epoll_event event;
    recv_cmd_t *cmd = (recv_cmd_t*)malloc(sizeof(recv_cmd_t));
    if (cmd == NULL)
    {   
        printf("add fd malloc cmd error!\n");   
        return;
    }   
    memset(cmd, 0x00, sizeof(recv_cmd_t));
    cmd->fd = fd; 
    cmd->len = 0;
    event.data.ptr = cmd;

    printf("add fd cmd:%p\n", cmd);

    event.events  = EPOLLIN;
    if(enable_et){
        event.events |= EPOLLET;
    }   
    ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event );
    if (ret != 0)
    {
        perror("epoll_ctl error");
        return ;
    }
    setnonblocking(fd);
}

void do_event(struct epoll_event* events, int number, int epollfd, int listenfd)
{
    int i=0;
    int ret = 0;
    struct in_addr addr1, addr2;
    char buf_src[64] = {0};
    char buf_dst[64] = {0};

    for(i =0; i<number; i++){
        recv_cmd_t *cmd = (recv_cmd_t *)events[i].data.ptr;
        int sockfd = cmd->fd;
        if(sockfd == listenfd) {
            struct sockaddr_in client_address;
            socklen_t client_addrlength = sizeof(client_address);
            int connfd = accept(listenfd, (struct sockaddr* )&client_address, &client_addrlength);
            if (connfd < 0)
            {
                perror("accept error");
                return;
            }
            addfd(epollfd, connfd, true);/*对connfd开启ET模式*/
            printf("server fd %d adding client on fd %d\n", listenfd, connfd);
        }else if(events[i].events & EPOLLIN) {
            ret = read(sockfd, cmd->buf+cmd->len, BUFFER_SIZE - cmd->len);
            if(ret <= 0) {
                if(errno == EAGAIN || errno == EWOULDBLOCK){
                    continue;
                }else{
                    // 
                }

                ret = epoll_ctl(epollfd, EPOLL_CTL_DEL, sockfd, &events[i]);
                printf("epoll_ctl_del ret = %d\n", ret);
                close(cmd->fd);
                free(cmd);
                continue;
            }

            cmd->len += ret;
            if (cmd->len < 12) {
                printf("recv fd=%d, len:%d too short!\n", events[i].data.fd, ret);
                continue;
            }

            memcpy(&addr1, cmd->buf+4, 4);  //复制IP地址
            sprintf(buf_src, "%s", inet_ntoa(addr1));
            memcpy(&addr2, cmd->buf+8, 4);  //复制IP地址
            sprintf(buf_dst, "%s", inet_ntoa(addr2));


            printf("msg:%x,%x,%d,%s,%s \n", cmd->buf[0], cmd->buf[1], ntohs(*(unsigned short*)(cmd->buf+2)), buf_src, buf_dst);

            buf_src[0] = 0x05;
            buf_src[1] = 0x00;
            ret = write(sockfd, buf_src, 2);
            printf("serving write client on fd %d, %d\n", sockfd, ret);
        }else{
            printf("something else happen\n");
        }
    }
}


int main()
{
    int ret = 0;
    int opt = 1;
    struct sockaddr_in address;
    bzero(&address, sizeof(address));

    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd < 0)
    {
        perror("socket error");
        return -1;
    }

    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt));

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = htonl(INADDR_ANY);
    address.sin_port = htons(8888);

    ret = bind(listenfd, (struct sockaddr *)&address, sizeof(address));
    if (ret != 0)
    {
        perror("bind error");
        return -1;
    }

    ret = listen(listenfd, 5);
    if (ret != 0)
    {
        perror("listen error");
        return -1;
    }

    struct epoll_event *events;
    events = (struct epoll_event *)malloc(MAX_EVENT_NUMBER * sizeof(struct epoll_event));
    memset(events, 0x00, sizeof(events));
    int epollfd = epoll_create(5);
    assert(epollfd != -1);

    addfd(epollfd, listenfd, true);/*对connfd开启ET模式*/

    while(1){
        int ret = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1);
        if(ret<0){
            printf("epoll wait failure\n");
            break;
        }
        do_event(events, ret, epollfd, listenfd);
    }
    close(listenfd);
    return 0;
}

client.c

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

int main() 
{ 
    int client_sockfd; 
    int len; 
    struct sockaddr_in address;//服务器端网络地址结构体 
    int result; 
    unsigned char buf[128] = {0}; 
    client_sockfd = socket(AF_INET, SOCK_STREAM, 0);//建立客户端socket 
    address.sin_family = AF_INET; 
    address.sin_addr.s_addr = inet_addr("127.0.0.1");
    address.sin_port = htons(8888); 
    len = sizeof(address); 
    result = connect(client_sockfd, (struct sockaddr *)&address, len); 
    if(result == -1) 
    {   
        perror("oops: client2"); 
        exit(1); 
    }   
    printf("client_sockfd = %d\n", client_sockfd); 

    buf[0] = 0x05;
    buf[1] = 0x09;

    int appaddr = inet_addr("192.168.9.112");
    int appaddr1 = inet_addr("192.168.9.113");
    unsigned short appport = htons(8080);
    memcpy(buf + 2, &appport, sizeof(appport)); 

    write(client_sockfd, buf, 4); 
    sleep(1);

    memcpy(buf, &appaddr, sizeof(appaddr));
    memcpy(buf + 4, &appaddr1, sizeof(appaddr1));

    write(client_sockfd, buf, 8); 
    printf("first client write over!\n");
    result = read(client_sockfd, buf, sizeof(buf));
    printf("from server len:%d %x,%x \n",result, buf[0], buf[1]); 

    close(client_sockfd);

    return 0;  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值