资讯专栏INFORMATION COLUMN

基于linux原生异步io创建的简易聊天程序

xcold / 358人阅读

摘要:分为两个独立的程序编译前先确定自己服务器的地址,比如想要在自己的下运行,先获取自己的地址,修改,里面的地址为自己的地址服务端编译运行客户端编译运行服务端先运行起来后,再启动客户端,可以在多态机器上启多个客户端,互相聊天

分为两个独立的程序
编译前先确定自己服务器的地址,比如想要在自己的ubuntu下运行,先ip addr获取自己的ip地址,修改chat_server.c,chat_client.c里面的ip地址为自己的ip地址

服务端chat_server.c
编译: gcc chat_server.c -o server
运行: ./server

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define    MAX_USER        500
#define    MAX_MSG_LEN        1024
#define MAX_IO_RETRY_TIMES    5

int server_fd;

int user_cnt = 0;
int user_fds[MAX_USER];

char msg_buffer[MAX_MSG_LEN];

void down()
{
    int i;
    for(i = 0; i < user_cnt; i++)
    {
        shutdown(user_fds[i], SHUT_RDWR);
        close(user_fds[i]);
        user_fds[i] = 0;
    }
    shutdown(server_fd, SHUT_RDWR);
    close(server_fd);
    server_fd = 0;
}

int go_on = 1;
void sig_handler(int signal)
{
    go_on = 0;
}

int my_safe_read(int fd)
{
    int ret;
    int i;
    
    for(i = 0; i < MAX_IO_RETRY_TIMES; i++)
    {
        errno = 0;
        int ret = read(fd, msg_buffer, MAX_MSG_LEN);
        if(ret < 0)
        {
            if(EAGAIN == errno || EWOULDBLOCK == errno)
            {
                printf("Safe read [%d] cnt
", i + 1);
                continue;
            }
            else
            {
                return ret;
            }
        }
        else if(0 == ret)
        {
            return 0;
        }
        else
        {
            return ret;
        }
    }
    return ret;
}

int my_safe_write(int fd)
{
    write(fd, msg_buffer, MAX_MSG_LEN);
}

int main(int argc, char *argv[])
{
    signal(SIGINT, sig_handler);
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == server_fd)
    {
        printf("socket err
");
        return -1;
    }
    printf("socket ok
");

    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    unsigned short portnum = 0x8888;
    if(argc >= 2)
    {
        int port = atoi(argv[1]);
        if(port > 20000)
        {
            portnum = port;
        }
    }
    printf("port = %d
", portnum);
    
    server_addr.sin_port = portnum;

    if(-1 == bind(server_fd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)))
    {
        printf("bind err
");
        return -1;
    }
    printf("bind ok
");

    if(-1 == listen(server_fd, MAX_USER))
    {
        printf("listen err
");
        return -1;
    }
    printf("listen ok
");

    int i;
    fd_set fds;
    struct timeval tv;
    while(go_on)
    {
        FD_ZERO(&fds);
        FD_SET(server_fd, &fds);
        for(i = 0; i < user_cnt; i++)
        {
            printf("-%d
", user_fds[i]);
            if(user_fds[i])
            {
                FD_SET(user_fds[i], &fds);
            }
        }

        int fd_cnt_to_selected = 0;
        for(i = 0; i < user_cnt; i++)
        {
            if(user_fds[i] > fd_cnt_to_selected)
            {
                fd_cnt_to_selected = user_fds[i];
            }
        }
        fd_cnt_to_selected = (0 == user_cnt)? (server_fd + 1) : (fd_cnt_to_selected + 1);

        tv.tv_sec = 2;
        tv.tv_usec = 0;
        int ret = select(fd_cnt_to_selected, &fds, 0, 0, &tv);
        if(ret < 0)
        {
            printf("select err
");
            break;
        }
        else if(0 == ret)
        {
            continue;
        }

        struct sockaddr_in client_addr;
        for(i = 0; i < user_cnt; i++)
        {
            if(FD_ISSET(user_fds[i], &fds))
            {
                bzero(msg_buffer, MAX_MSG_LEN);
                int ret = my_safe_read(user_fds[i]);
                if(ret <= 0)
                {
                    int connection_state = 1; 
                    int len_of_int = sizeof(int);
                    getsockopt(user_fds[i], IPPROTO_TCP, SO_KEEPALIVE, (void*)&connection_state, &len_of_int); 
                    printf("connection_state = %s
", (0 == connection_state)? "break" : "alive");
                    if(0 == connection_state)
                    {
                        close(user_fds[i]);
                        FD_CLR(user_fds[i], &fds);
                        if(user_cnt - 1 == i)
                        {
                            user_cnt = user_cnt - 1;
                            user_fds[i] = 0;
                        }
                        else
                        {
                            int j;
                            for(j = i; j < user_cnt; j++)
                            {
                                user_fds[j] = user_fds[j+1];
                            }
                            user_fds[j] = 0;
                            user_cnt = user_cnt -1;
                        }
                    }
                }
                else
                {
                    printf("receive[%s]
", msg_buffer);
                    int j;
                    for(j = 0; j < user_cnt; j++)
                    {
                        if(j == i)
                        {
                            continue;
                        }
                        my_safe_write(user_fds[j]);
                    }
                }
            }
        }

        if(FD_ISSET(server_fd, &fds))
        {
            int sin_size = sizeof(struct sockaddr);
        
            user_fds[user_cnt] = accept(server_fd, (struct sockaddr *)(&client_addr), &sin_size);
            if(-1 == user_fds[user_cnt])
            {
                printf("accept err
");
                return -1;
            }
            printf("accept ok!
");
            printf("user_fds[user_cnt] = %d
", user_fds[user_cnt]);
            user_cnt++;
        }
    }
    
    down();
    return 0;
}

客户端chat_client.c
编译: gcc chat_client -lpthread -o chat_client
运行: 服务端先运行起来后,再启动客户端,可以在多态机器上启多个客户端,互相聊天
./chat_client

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int cfd = 0;
struct passwd *pwd;

void sig_handler(int signal)
{
    char bye_msg[1024] = { 0 };
    sprintf(bye_msg, "WARNING------>User[%s] have go, he said all is "SB"! Oh, what the fuck!", pwd->pw_name);
    write(cfd, bye_msg, 1024);
    
    shutdown(cfd, SHUT_RDWR);
    close(cfd);
    cfd = 0;
    exit(-1);
}

void* f(void* t)
{
    struct timeval tv;
    fd_set fds;
    while(1)
    {
        tv.tv_sec = 0;
        tv.tv_usec = 100;
        FD_ZERO(&fds);
        FD_SET(cfd, &fds);
        
        int r = select(cfd + 1, &fds, 0, 0, &tv);
        if(r<0)
        {
            printf("select err
");
        }
        else if(r==0)
        {
        }
        
        char buf[1024*10] = { 0 };
        int n = read(cfd, buf, 1024*10);
        if(buf[0] != 0)
            printf("%s
", buf);
    }    
}

int main(int argc, char * argv[])
{
    signal(SIGINT, sig_handler);
    pwd = getpwuid(getuid());

    int recbytes;
    int sin_size;
    char buffer[1024] ={0}; 
    struct sockaddr_in s_add, c_add;
    unsigned short portnum =0x8888;
    if(argc >= 2)
    {
        int port = atoi(argv[1]);
        if(port > 20000)
        portnum = port;
    }
    printf("port = %d
", portnum);
    
    cfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == cfd)
    {
        printf("socket err
");
        return -1;
    }
    //printf("socket ok
");

    bzero(&s_add, sizeof(struct sockaddr_in));
    s_add.sin_family = AF_INET;
    s_add.sin_addr.s_addr = inet_addr("192.168.60.104");
    s_add.sin_port = htons(portnum);
    
    if(-1 == connect(cfd, (struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
    {
        printf("connect err
");
        return -1;
    }
    char personal_info[128] = { 0 };
    sprintf(personal_info, "DouBi[%s] is comming!!!HaHaaa^-^", pwd->pw_name);
    write(cfd, personal_info, 128);
    //printf("connect ok
");

    pthread_t th;
    int rr = pthread_create((pthread_t *)&th, NULL, f, NULL);
    
    while(1)
    {    
        //printf("enter what you want to say:_
");
        char b[10240] = { 0 };
        sprintf(b, "[%s]: ", pwd->pw_name);
        gets(b + strlen(b));
        //printf("b = %s
", b);
        if(-1 == (recbytes = write(cfd, b, 1024*10)))
        {
            printf("send data err
");
            return -1;
        }
        //printf("send ok
");
    }
    

    //close(cfd);
//    sleep(100);
    
    return 0;
}


文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/25004.html

相关文章

  • 利用express+socket.io实现一个简易聊天

    摘要:用伪代码来模拟下长轮询的过程前端利用下面函数进行请求后端代码做如下更改利用随机数的大小来模拟是否有新数据有新数据来了长轮询的确减少了请求的次数,但是它也有着很大的问题,那就是耗费服务器的资源。 写在前面 最近由于利用node重构某个项目,项目中有一个实时聊天的功能,于是就研究了一下聊天室,在线demo|源码,欢迎大家反馈。这个聊天室的主要利用到了socket.io和express。这个...

    Chaz 评论0 收藏0
  • 基于express和socket.io简易聊天

    摘要:简易版聊天室技术栈功能实现实时聊天创建房间表情包完善私聊效果登录服务端判断之前是否登录过聊天室,如果是则直接进入聊天室,否则跳转到登录页面。客户端发送创建房间和切换房间的事件给服务端。 Chat 简易版聊天室 技术栈 express socket.io 功能 实现 实时聊天 创建房间 表情包 完善 私聊 效果 登录 showImg(https://segmentfa...

    dendoink 评论0 收藏0
  • PHP并发IO编程之路

    摘要:下文如无特殊声明将使用进程同时表示进程线程。收到数据后服务器程序进行处理然后使用向客户端发送响应。现在各种高并发异步的服务器程序都是基于实现的,比如。 并发 IO 问题一直是服务器端编程中的技术难题,从最早的同步阻塞直接 Fork 进程,到 Worker 进程池/线程池,到现在的异步IO、协程。PHP 程序员因为有强大的 LAMP 框架,对这类底层方面的知识知之甚少,本文目的就是详细介...

    Riddler 评论0 收藏0
  • 微信小程序资源汇总

    awesome-github-wechat-weapp 是由OpenDigg整理并维护的微信小程序开源项目库集合。我们会定期同步上的项目到这里,也欢迎各位 UI组件开发框架实用库开发工具服务端项目实例Demo UI组件 weui-wxss ★1873 - 同微信原生视觉体验一致的基础样式库zanui-weapp ★794 - 好用易扩展的小程序 UI 库wx-charts ★449 - 微信小程...

    Olivia 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<