聊天室源码分析

实现功能

在这里插入图片描述

模型

服务器

使用了epoll模型,并为每一个处理请求新开一个线程进行处理,并进行线程分离,使它们结束后可以自动释放资源。如果使用线程池自然是更好的,但本人能力不足怕写成多线程难以处理。
epoll模型如下

   for(;;)
    {   
        nfds = epoll_wait(epfd,events,EVENTS_MAX_SIZE,-1);//等待可写事件
        for(int i=0;i<nfds;i++)
        {
            if(events[i].data.fd==sock_fd)       //服务器套接字接收到一个连接请求
            {
                if(connect_size>MAX_CONTECT_SIZE)
                {
                    printf("%d %d\n",connect_size,nfds);
                    sleep(3);
                    perror("到达最大连接数!\n");
                    break;
               //     continue;
                }
                cliaddr_len=sizeof(cliaddr);
                conn_fd=accept(events[i].data.fd,(struct sockaddr*)&cliaddr,&cliaddr_len);
                if(conn_fd<=0)
                {
                    perror("error in accept\n");
                    printf("%s\n",strerror(errno));
                 //   continue;
                 break;
                }
                 connect_size++;
                 printf("received from %s at PORT %d\n",inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str)),ntohs(cliaddr.sin_port));
                

                ev.data.fd= conn_fd;
                ev.events =EPOLLIN | EPOLLONESHOT | EPOLLRDHUP;
                epoll_ctl(epfd,EPOLL_CTL_ADD,conn_fd,&ev);

            }
/*       
*/
            else{
                temp->epfd=epfd;
                temp->conn_fd=events[i].data.fd;
                pth1=pthread_create(&pth1,NULL,solve,temp);
            }
        }
    }

采用阻塞的方式等待可读事件,我们为每一個收到的请求单独开一个线程进行处理。

服务器存储消息

服务器将接受到的信息都调用mysql接口存储在数据库中。

客户端

客户端采用了简单的单线程方法,单独开一个线程持续的接受信息并进行处理,而主函数则只对处理完的信息进行显示。
在这里插入图片描述

传输信息

服务器和客户端之间使用传输一个定长的结构体

struct work {
    char tye; //种类
    int sid; //发送者
    int rid; //接受者
    char name[20]; //名字
    char password[20]; //密码
    int ret; //返回值
    char mes[1000]; //信息
};

虽然显得很笨重,但却很简单。

处理信息

无论是客户端还是服务器,受到一个操作请求时就会先辨别tye,然后再进入专门处理的函数对信息进行处理。
当我们进行操作完成,需要发送一个标志代表处理已经完成。
比如说,客户端希望获取未读信息时,就会向服务器发送请求,并进行等待,服务器受到请求后会逐条发送信息,发送完毕后再发送一个特殊的标志代表该动作已经完成。收到标志后,客户端才会对处理完成的信息进行读取。

客户端存储消息

客户端把消息消息存储在链表中,在本程序中定义了诸多宏函数在List.h中来对链表进行处理。无论是未读信息,还是已读信息,好友列表,文件列表,群信息,群列表都存储在客户端的链表中。在需要时,客户端会对链表中的信息进行更新。

typedef struct {
int sid;
int rid;
char mes[1000];
}mes;
typedef struct mes_node{
    mes data;
    struct mes_node*prev;
    struct mes_node*next;
}mes_node_t,*mes_list_t;

发送文件与接受文件

我们使用sendfile函数来发送一个文件,但是这里有一个问题,那就是接收方需要知道文件的大小。所以当一方表明要发送文件时,会先将文件名和大小发送过去。发送用sendfile会很简单,但接受时就得老实的调用recv来循环接受文件。

  //接受文件,len为文件的大小
  out=creat(filename,0664);
        int len=s1.ret;
        char buf[5000];
        while(len>0 ){
            memset(buf,'\0',sizeof(buf));
            num=recv(s->conn_fd,buf,4096,0); 
            len=len-num;
            write(out,buf,num);
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值