Linux下poll函数实现多用户聊天

Client:

#define _GNU_SOURCE 1
#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 <string.h>
#include <stdlib.h>
#include <poll.h>
#include <fcntl.h>

#define BUFFER_SIZE 64

int main()
{
    const char *ip="127.0.0.1";
    int port=12345;
    struct sockaddr_in server_address;
    bzero(&server_address,sizeof(server_address));
    server_address.sin_family=AF_INET;
    inet_pton(AF_INET,ip,&server_address.sin_addr);
    server_address.sin_port=htons(port);

    int sockfd=socket(PF_INET,SOCK_STREAM,0);
    assert(sockfd!=0);
    if(connect(sockfd,(struct sockaddr *)&server_address,sizeof(server_address))<0)
    {
        printf("connection failed\n");
        close(sockfd);
        return 1;
    }

    struct pollfd fds[2];
    fds[0].fd=0;
    fds[0].revents=0;
    fds[1].fd=sockfd;
    fds[1].events=POLLIN | POLLRDHUP;
    fds[1].revents=0;

    char read_buf[BUFFER_SIZE];
    int pipefd[2];
    int ret=pipe(pipefd);
    assert(ret!=-1);
    while(1)
    {
        ret=poll(fds,2,-1);
        if(ret<0)
        {
            printf("poll failure\n");
            break;
        }

        if(fds[1].revents&POLLRDHUP)
        {
            printf("server close the connection\n");
            break;
        }
        else if(fds[1].revents&POLLIN)
        {
            memset(read_buf,'\0',BUFFER_SIZE);
            recv(fds[1].fd,read_buf,BUFFER_SIZE-1,0);
            printf("%s\n",read_buf);
        }
        if(fds[0].revents&POLLIN)
        {
            ret=splice(0,NULL,pipefd[1],NULL,32768,SPLICE_F_MORE | SPLICE_F_MOVE);
            ret=splice(pipefd[0],NULL,sockfd,NULL,32768,SPLICE_F_MORE |SPLICE_F_MOVE);
        }
    }
    close(sockfd);
    return 0;
}

Server:

#define _GNU_SOURCE 1
#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 <poll.h>

#define USER_LIMIT 5
#define BUFFER_SIZE 64
#define FD_LIMIT 65535

struct client_data
{
    struct sockaddr_in address;
    char *write_buf;
    char buf[BUFFER_SIZE];
};

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;
}

int main()
{
    const char *ip="127.0.0.1";
    int port=12345;
    int ret=0;
    int i,j;
    struct sockaddr_in address;
    bzero(&address,sizeof(address));
    address.sin_family=AF_INET;
    inet_pton(AF_INET,ip,&address.sin_addr);
    address.sin_port=htons(port);
   // address.sin_addr.s_addr=INADDR_ANY;
    int listenfd=socket(PF_INET,SOCK_STREAM,0);
    assert(listenfd>=0);

    ret=bind(listenfd,(struct sockaddr *)&address,sizeof(address));
    assert(ret!=-1);
    ret=listen(listenfd,5);
    assert(ret!=-1);
    struct client_data* users=(struct client_data*) calloc(FD_LIMIT,sizeof(struct client_data));
    struct pollfd fds[USER_LIMIT+1];
    int user_counter=0;
    for(i=1;i<=USER_LIMIT;++i)
    {
        fds[i].fd=-1;
        fds[i].events=0;
    }

    fds[0].fd=listenfd;
    fds[0].events=POLLIN | POLLERR;
    fds[0].revents=0;

    while(1)
    {
        printf("{\n");
        ret=poll(fds,user_counter+1,-1);
        printf("}\n");
        if(ret<0)
        {
            printf("poll failure\n");
            break;
        }

        for(i=0;i<user_counter+1;++i)
        {

            if((fds[i].fd==listenfd)&&(fds[i].revents&POLLIN))
            {
                struct sockaddr_in client_address;
                socklen_t client_addrlengh=sizeof(client_address);
                int connfd=accept(listenfd,(struct sockaddr *)&client_address,&client_addrlengh);
                if(connfd<0)
                {
                    printf("errno is:%d\n",errno);
                    continue;
                }
                if(user_counter>=USER_LIMIT)
                {
                    const char *info="too many users\n";
                    printf("%s",info);
                    send(connfd,info,strlen(info),0);
                    close(connfd);
                    continue;
                }
                user_counter++;
                users[connfd].address=client_address;
                setnonblocking(connfd);
                fds[user_counter].fd=connfd;
                fds[user_counter].events=POLLIN |POLLRDHUP|POLLERR;
                fds[user_counter].revents=0;
                printf("comes a new user,now have %d users\n",user_counter);
            }
            else if(fds[i].revents&POLLERR)
            {
                printf("get an error from %d \n",fds[i].fd);
                char errors[100];
                memset(errors,'\0',100);
                socklen_t length=sizeof(errors);
                if(getsockopt(fds[i].fd,SOL_SOCKET,SO_ERROR,&errors,&length)<0)
                {
                    printf("get socket option failed\n");
                }
                continue;
            }
            else if(fds[i].revents&POLLRDHUP)
            {
                users[fds[i].fd]=users[fds[user_counter].fd];
                close(fds[i].fd);
                fds[i]=fds[user_counter];
                i--;
                user_counter--;
                printf("a client left\n");
            }
            else if(fds[i].revents&POLLIN)
            {
                int connfd=fds[i].fd;
                memset(users[connfd].buf,'\0',BUFFER_SIZE-1);
                ret=recv(connfd,users[connfd].buf,BUFFER_SIZE-1,0);
                if(ret<0)
                {
                    if(errno!=EAGAIN)
                    {
                        close(connfd);
                        users[fds[i].fd]=users[fds[user_counter].fd];
                        fds[i]=fds[user_counter];
                        i--;
                        user_counter--;
                    }
                }
                else if(ret==0)
                {
                }
                else
                {
                    for(j=1;j<=user_counter;++j)
                    {
                        if(fds[j].fd==connfd)
                        {
                            continue;
                        }
                        fds[j].events |=~POLLIN;
                        fds[j].events |=POLLOUT;
                        users[fds[j].fd].write_buf=users[connfd].buf;
                    }
                }
            }
            else if(fds[i].revents&POLLOUT)
            {
                int connfd=fds[i].fd;
                if(!users[connfd].write_buf)
                {
                    continue;
                }
                ret=send(connfd,users[connfd].write_buf,strlen(users[connfd].write_buf),0);
                users[connfd].write_buf=NULL;
                fds[i].events |=~POLLOUT;
                fds[i].events |=POLLIN;
            }
        }
    }
    free(users);
    close(listenfd);
    return 0;
}
时间: 2024-10-09 00:55:05

Linux下poll函数实现多用户聊天的相关文章

对于linux下system()函数的深度理解(整理)

对于linux下system()函数的深度理解(整理) (2013-02-07 08:58:54) 这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数中调用的命令也都一切正常.就没理这个bug,以为是其他的代码影响到这个,或是内核驱动文件系统什么的异常导致,昨天有出现了这个问题,就随手百了一下度,问题出现了,很多人都说system()函数要慎用要少用要能不用则不用,system()函数不稳定?

Linux下Kill函数用法

http://www.cnblogs.com/winnxm/archive/2010/01/22/1654502.html [ KILL ]功能描述: 用于向任何进程组或进程发送信号. 1 #include <sys/types.h> 2 3 #include <signal.h> 4 5 int kill(pid_t pid, int sig); 6 7 参数: pid:可能选择有以下四种 1. pid大于零时,pid是信号欲送往的进程的标识. 2. pid等于零时,信号将送往所

【C/C++】Linux下system()函数引发的错误

http://my.oschina.net/renhc/blog/54582 [C/C++]Linux下system()函数引发的错误 恋恋美食  恋恋美食 发布时间: 2012/04/21 11:33 阅读: 11393 收藏: 21 点赞: 8 评论: 4 今天,一个运行了近一年的程序突然挂掉了,问题定位到是system()函数出的问题,关于该函数的简单使用在我上篇文章做过介绍: http://my.oschina.net/renhc/blog/53580 先看一下问题 简单封装了一下sys

Linux下select函数的使用

Linux下select函数的使用 转载:http://www.cnblogs.com/hjslovewcl/archive/2011/03/16/2314330.html 一.Select 函数详细介绍 Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect. accept.recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发 生,

Linux下system()函数引发的错误

先看一下问题 简单封装了一下system()函数: 1 int pox_system(const char *cmd_line) 2 { 3     return system(cmd_line); 4 } 函数调用: 1 int ret = 0; 2 ret = pox_system("gzip -c /var/opt/I00005.xml > /var/opt/I00005.z"); 3 if(0 != ret) 4 { 5     Log("zip file fa

[Android Memory] Linux下malloc函数和OOM Killer

http://www.linuxidc.com/Linux/2010-09/28364.htm Linux下malloc函数主要用来在用户空间从heap申请内存,申请成功返回指向所分配内存的指针,申请失败返回NULL.默认情况下,Linux内核使用“乐观的”分配内存策略,首先粗略估计系统可使用的内存数,然后分配内存,但是在使用的时候才真正把这块分配的内存给你.这样一来,即使用malloc申请内存没有返回NULL,你也不一定能完全使用这块内存,特别是在一次或连续多次申请很多内存的时候. 如果一直连

Linux下system函数

http://www.jb51.net/article/40517.htm   浅析如何在c语言中调用Linux脚本 http://blog.csdn.net/koches/article/details/7552034 C语言system()函数 http://blog.csdn.net/lazy_tiger/article/details/1771705 System函数与脚本的后台执行 Linux下system函数

Linux下c函数dlopen实现加载动态库so文件代码举例

dlopen()是一个强大的库函数.该函数将打开一个新库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了.可以在自己的程序中使用 dlopen().dlopen() 在 dlfcn.h 中定义,并在 dl 库中实现.它需要两个参数:一个文件名和一个标志.文件名就是一个动态库so文件,标志指明是否立刻计算库的依赖性.如果设置为 RTLD_NOW 的话,则立刻计算:如果设置的是 RTLD_LAZY,则在需要

linux 下 poll 编程

poll 与 select 很类似,都是对描述符进行遍历,查看是否有描述符就绪.如果有就返回就绪文件描述符的个数将.poll 函数如下: #include <poll.h> int poll(struct pollfd *fdarray, unsigned long nfds, int timeout) 第一个参数指向结构数组第一个元素的指针,每个数组都是一个 pollfd 结构iouyonghu制定额是某个给定描述符的条件. struct pollfd { int fd; short eve