达内LOGO和北京达内网址达内科技培训项目:Java培训 3G培训 Android培训 软件测试培训北京达内服务电话
java培训
用epoll实现简易的telnet
 我承认这篇文章有点标题党,呵呵。其实就是一个能和服务器建立全双工通信的客户端而已,用epoll机制实现。
    上代码:
    [cpp]
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/epoll.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <errno.h>
    //注意,不能一次性输入超过MAXLINE个的字符,否则程序会出错
    #define MAXLINE 1024
    //发生了致命错误,输出错误后立即退出
    void error_quit(const char *str)
    {
    perror(str);
    exit(1);
    }
    //关闭连接,退出程序
    void close_connect(int sockfd)
    {
    close(sockfd);
    printf("The connect have shutdown\n");
    exit(0);
    }
    int main(int argc, char **argv)
    {
    int epfd, sockfd, nfs, tfd;
    int readn, i, res;
    struct sockaddr_in servaddr;
    struct epoll_event ev, events[256];
    char buffer[MAXLINE];
    if( argc != 3 )
    error_quit("usage: mytelnet <Address> <Port>");
    //创建epoll事件处理机
    epfd = epoll_create(256);
    if( -1 == epfd )
    error_quit("epoll_create error");
    //创建用于TCP协议的套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons( atoi(argv[2]) );
    res = inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
    //连接服务器
    if( res != 1 )
    error_quit("inet_pton error");
    res = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    if( res < 0 )
    error_quit("connect error");
    //注册socket事件
    ev.data.fd = sockfd;
    ev.events = EPOLLIN|EPOLLET;
    res = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
    if( res < 0 )
    error_quit("epoll_ctl error");
    //注册标准输入事件
    ev.data.fd = STDIN_FILENO;
    ev.events = EPOLLIN|EPOLLET;
    res = epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev);
    if( res < 0 )
    error_quit("epoll_ctl error");
    //开始事件循环
    while( 1 )
    {
    nfs = epoll_wait(epfd, events, 20, 500);
    for(i=0; i<nfs; i++)
    {
    if(events[i].events & EPOLLIN)
    {
    tfd = events[i].data.fd;
    memset(buffer, 0, MAXLINE);
    readn = read(tfd, buffer, MAXLINE);
    //有网络消息传来了
    if( sockfd == tfd )
    {
    if ( readn < 0)
    {
    // Connection Reset:你连接的那一端已经断开了,
    //而你却还试着在对方已断开的socketfd上读写数据!
 if (errno == ECONNRESET)
    close_connect(sockfd);
    else
    error_quit("read error");
    }
    //连接正常关闭
    else if ( readn == 0 )
    close_connect(sockfd);
    else
    printf("%s", buffer);
    }
    //标准输入
    if( STDIN_FILENO == tfd )
    {
    ev.data.fd = sockfd;
    ev.events = EPOLLOUT|EPOLLET;
    res = epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
    if( -1 == res )
    error_quit("epoll_ctl error");
    }
    }
    //如果有数据发送
    else if(events[i].events & EPOLLOUT)
    {
    sockfd = events[i].data.fd;
    write(sockfd, buffer, readn);
    //注册用于读操作的文件描述符和事件
    ev.data.fd = sockfd;
    ev.events = EPOLLIN|EPOLLET;
    res = epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
    if( -1 == res )
    error_quit("epoll_ctl error");
    }
    }
    }
    return 0;
    }
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/epoll.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <errno.h>
    //注意,不能一次性输入超过MAXLINE个的字符,否则程序会出错
    #define MAXLINE 1024
    //发生了致命错误,输出错误后立即退出
    void error_quit(const char *str)
    {
    perror(str);
    exit(1);
    }
    //关闭连接,退出程序
    void close_connect(int sockfd)
    {
    close(sockfd);
    printf("The connect have shutdown\n");
    exit(0);
    }
    int main(int argc, char **argv)
    {
    int epfd, sockfd, nfs, tfd;
    int readn, i, res;
    struct sockaddr_in servaddr;
    struct epoll_event ev, events[256];
    char buffer[MAXLINE];
    if( argc != 3 )
    error_quit("usage: mytelnet <Address> <Port>");
    //创建epoll事件处理机
    epfd = epoll_create(256);
    if( -1 == epfd )
    error_quit("epoll_create error");
    //创建用于TCP协议的套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons( atoi(argv[2]) );
    res = inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
    //连接服务器
    if( res != 1 )
    error_quit("inet_pton error");
    res = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    if( res < 0 )
    error_quit("connect error");
    //注册socket事件
    ev.data.fd = sockfd;
    ev.events = EPOLLIN|EPOLLET;
    res = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
    if( res < 0 )
    error_quit("epoll_ctl error");
    //注册标准输入事件
    ev.data.fd = STDIN_FILENO;
    ev.events = EPOLLIN|EPOLLET;
    res = epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev);
    if( res < 0 )
    error_quit("epoll_ctl error");
    //开始事件循环
    while( 1 )
    {
    nfs = epoll_wait(epfd, events, 20, 500);
    for(i=0; i<nfs; i++)
    {
    if(events[i].events & EPOLLIN)
    {
    tfd = events[i].data.fd;
    memset(buffer, 0, MAXLINE);
    readn = read(tfd, buffer, MAXLINE);
    //有网络消息传来了
    if( sockfd == tfd )
    {
    if ( readn < 0)
    {
    // Connection Reset:你连接的那一端已经断开了,
    //而你却还试着在对方已断开的socketfd上读写数据!
    if (errno == ECONNRESET)
    close_connect(sockfd);
    else
    error_quit("read error");
    }
    //连接正常关闭
    else if ( readn == 0 )
    close_connect(sockfd);
    else
    printf("%s", buffer);
    }
    //标准输入
    if( STDIN_FILENO == tfd )
    {
    ev.data.fd = sockfd;
    ev.events = EPOLLOUT|EPOLLET;
    res = epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
    if( -1 == res )
    error_quit("epoll_ctl error");
    }
    }
    //如果有数据发送
    else if(events[i].events & EPOLLOUT)
    {
    sockfd = events[i].data.fd;
    write(sockfd, buffer, readn);
    //注册用于读操作的文件描述符和事件
    ev.data.fd = sockfd;
    ev.events = EPOLLIN|EPOLLET;
    res = epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
    if( -1 == res )
    error_quit("epoll_ctl error");
    }
    }
    }
    return 0;
    }
    编译与运行命令:
    gcc mytelnet.c -o mytelnet -levent
    ./mytelnet 127.0.0.1 8877