基于linux服务器的epoll多用户通讯代码

本文介绍了一种使用epoll技术构建的多用户聊天应用,详细阐述了如何利用epoll实现用户uid与套接字的对应关系,以及如何处理读写操作的阻塞问题。代码能够顺利编译并通过调试,支持广播所有在线id对话,并具有良好的扩展性。

最近接触到服务器编程,基于select、poll、epoll的选择相信很多文章已经有详细的介绍。本文主要介绍epoll的聊天代码,google发现epoll例程大部分都是服务器与客服端通讯,而现实中多用户聊天均涉及到客服端与客服端之间通讯。现将源码贴出,主要是将套接字记录保存下来实现用户uid与套接字的对应关系,及读与写的阻塞与否。代码能编译通过调试,为广播全部在线id对话,可扩展,若有疑问,可留言。

server:

#include <iostream>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
//#include <error.h>


using namespace std;


#define MAXLINE 500
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 5000
#define INFTIM 1000
#define PORT 8888


void setnonblocking(int sock)
{
    int opts;
    opts=fcntl(sock,F_GETFL);
    if(opts<0)
    {
        perror("fcntl(sock,GETFL)");
        exit(1);
    }
    opts = opts|O_NONBLOCK;
    if(fcntl(sock,F_SETFL,opts)<0)
    {
        perror("fcntl(sock,SETFL,opts)");
        exit(1);
    }
}


int main(int argc, char* argv[])
{
    int i, listenfd, connfd, sockfd,epfd,nfds, portnumber;
    ssize_t n;
    char line[MAXLINE];
    socklen_t clilen;
    int num[256];
int a =0;
int number;


memset(num, 0, sizeof(num));
   /* if ( 2 == argc )
    {
        if( (portnumber = atoi(argv[1])) < 0 )
        {
            fprintf(stderr,"Usage:%s portnumber/a/n",argv[0]);
            return 1;
        }
    }
    else
    {
        fprintf(stderr,"Usage:%s portnumber/a/n",argv[0]);
        return 1;
    }*/

portnumber = PORT;




    struct epoll_event ev,events[20];
    


    epfd=epoll_create(256);
    struct sockaddr_in clientaddr;
    struct sockaddr_in serveraddr;
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
   


    setnonblocking(listenfd);


  


    ev.data.fd=listenfd;
   


    ev.events=EPOLLIN;
    //ev.events=EPOLLIN;


    


    epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    const char *local_addr="127.0.0.1";
    inet_aton(local_addr,&(serveraddr.sin_addr));//htons(portnumber);


    serveraddr.sin_port=htons(portnumber);
    bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));
    listen(listenfd, LISTENQ);
   
    std::vector<int> fds;
    for ( ; ; ) {
       


        nfds=epoll_wait(epfd,events,20,500);
       


        for(i=0;i<nfds;++i)
        {
            if(events[i].data.fd==listenfd)


            {
                connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);
                
if(connfd<0){
                    perror("connfd<0");
                    exit(1);
                }
num[a] = connfd;
printf("num[i]  a %d %d\n",num[a],a);

a++;


printf("connfd %d\n",connfd);
                setnonblocking(connfd);


                char *str = inet_ntoa(clientaddr.sin_addr);
                cout << "accapt a connection from " << str << endl;
                


                ev.data.fd=connfd;
               


                ev.events=EPOLLIN;
                //ev.events=EPOLLIN;


              


                epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
            }
            else if(events[i].events&EPOLLIN)


            {
                cout << "EPOLLIN" << endl;
                n = recv(events[i].data.fd, line, MAXLINE, 0); 
if (n == 0) {
//socket close
close(events[i].data.fd);
}else if (n==-1) {
// socket error
perror("recv");
                        std::cout<<"readline error"<<std::endl;
printf("sockfd %d\n",sockfd);
exit(-1);
} else {
// recv data
for(number = 0;number < 256; number++)
{
if(num[number] != 0)
  {
printf("num %d  %d\n",num[number],nfds);
send(num[number], line, MAXLINE, 0);
}
}
}

            }
        }
    }
    return 0;
}


client:

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


#define MAXLINE 1000


using namespace std;




int main(int argc, char *argv[])
{
int sockfd, epfd, nfds, i;
int n;
struct sockaddr_in serv_addr;
char line[MAXLINE];


sockfd = socket(AF_INET, SOCK_STREAM, 0);
printf("sockfd 1 is %d\n",sockfd);
if(sockfd < 0)
{

}
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8888);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");



if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("connect is false\n");
}

struct epoll_event ev,events[20];
epfd=epoll_create(256);
ev.data.fd=sockfd;
    ev.events=EPOLLIN;
epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);
ev.data.fd = 1;
ev.events = EPOLLIN;
epoll_ctl(epfd,EPOLL_CTL_ADD,1,&ev);
while(1)
{
nfds=epoll_wait(epfd,events,20,500);
       
        for(i=0;i<nfds;++i)
        {


            if(events[i].events&EPOLLIN)


            {
                cout << "EPOLLIN" << endl;
if (events[i].data.fd == 1) {
// read from stdin
// then send to server
fgets(line, MAXLINE, stdin);
if(n = send(sockfd, line, MAXLINE, 0) < 0){
printf("send error \n");
}
continue;
}
                if ( (n = recv(sockfd, line, MAXLINE, 0)) < 0) {
                    if (errno == ECONNRESET) {
                        close(sockfd);
                        events[i].data.fd = -1;
                    } else
                        std::cout<<"readline error"<<std::endl;
                } else if (n == 0) {
                    close(sockfd);
                    events[i].data.fd = -1;
                }
                line[n] = '\0';
                cout << "read " << line << endl;
               
                ev.data.fd=sockfd;
                ev.events=EPOLLIN;
               


                epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
            }
        }


}
return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值