Linux服务器开发实战——QT控制界面+epoll聊天服务

io复用文章:https://blog.csdn.net/qq_25490573/article/details/102457943

部分函数:getpeername   根据句柄得到ip地址

                 struct sockaddr_storage addr;

                socklen_t len = sizeof(addr);

                 getpeername(fd,(struct sockaddr *)&addr,&len);

                 struct sockaddr_in *in = (struct sockaddr_in *)&addr;

                 inet_ntop(AF_INET,&IN->sin_addr,ipbuf,MAXBUFLEN);

                 strncmp(buffer, "end", 3)

循环读取只到完毕(解决粘包问题)

 char * packetptr;
 int isend nbytesneed bytesum;
while(nbytesneed>0)
{
	isend = read(epollfd,packetptr,nbytesneed);
	if(isend == -1||isend ==0)
		break;
	nbytesneed -=isend;
	packetptr += isend;
	bytesum += isend;
}

epoll端代码:

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "arpa/inet.h"
#include "sys/epoll.h"
#include "fcntl.h"
#include "stdlib.h"
#include <string.h>
 
#define SERVER_ADDR "127.0.0.1"
#define SERVER_PORT "6666"
#define CLIENT_NAMBER 128
struct epoll_event ep_ev;
int listen_sock,epoll_fd,control_sock=-1;
struct epoll_event ready_ev[128];
int maxnum = 128;
int timeout = 1000;//设置超时时间 若为-1则永久等待
int ret = 0;
int done = 0;
char buf[1024];
char * databuf;
static int recvstat = 0;
int clientnum[128] = {0};
int creat_socket(char *ip,char *port)
{
        int sock = socket(AF_INET,SOCK_STREAM,0);
        if(sock<0){
                perror("socket");
                exit(2);
        }
        int opt = 1;
        //设置socket 先断开时 避免进入time_wait状态,属性SO_REUSEADDR,是使其地址能够重用
        if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))<0)
        {
                perror("setsockopt");
                exit(3);
        }
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(atoi(port));
        local.sin_addr.s_addr = inet_addr(ip);
        if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
        {
                perror("bind");
                exit(4);
        }
        if(listen(sock,5)<0){
                perror("listen");
                exit(5);
        }
        printf("listen and bind succeed\n");
        return sock;
}
int set_noblock(int sock)
{
        int fl = fcntl(sock,F_GETFL);
        return fcntl(sock,F_SETFL,fl|O_NONBLOCK);
}
void Server_Init()
{
		databuf = (char*)malloc(1024*128);
		memset(databuf,'\0',sizeof(databuf));
	    listen_sock = creat_socket(SERVER_ADDR,SERVER_PORT);
        epoll_fd = epoll_create(255);
        if(epoll_fd <0)
        {
                perror("epoll_create");
                exit(6);
        }
        ep_ev.events = EPOLLIN;
        ep_ev.data.fd = listen_sock;
        if (epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listen_sock,&ep_ev)<0)
        {
                perror("epoll_ctl");
                exit(7);
        }
        clientnum[0] = listen_sock;
        memset(buf,'\0',sizeof(buf));
}
void creattoclient(int fd){
	for (int i = 0; i < CLIENT_NAMBER; ++i)
	{
		if(clientnum[i]!=0){

		}else
		{
			clientnum[i] = fd;
			return;
		}
	}
}
void deletetoclient(int fd){
	for (int i = 0; i < CLIENT_NAMBER; ++i)
	{
		if(clientnum[i]!=0){
			if(clientnum[i] == fd)
				clientnum[i] = 0;
		}else
		{
			return;
		}
	}
}
void Epoll_Listen()
{
	        while(!done)
        {
        	if (recvstat==1)
        	{
        		
        	}else if (recvstat == 0)
        	{
        		memset(databuf,'\0',sizeof(databuf));
        	}
        		
                switch(ret = epoll_wait(epoll_fd,ready_ev,maxnum,timeout))
                {
                        case -1:
                                perror("epoll_wait");
                                exit(8);
                        break;
                        case 0:
                        recvstat = -1;
                        //      perror("time out ...\n");
                        break;
                        default:
                //      printf("a new sigle!\n");       
                                for (int i = 0; i < ret; ++i)
                                {
 //判断是否是监听套接字,是的话accept
                                        int fd = ready_ev[i].data.fd;
                                        if ((fd==listen_sock)&&(ready_ev[i].events&EPOLLIN))
                                        {
                                                struct sockaddr_in remote;
                                                socklen_t len = sizeof(remote);
 
                                                int accept_sock = accept(listen_sock,(struct sockaddr*)&remote,&len);
                                                if (accept<0)
                                                {
                                                        perror("accept");
                                                        continue;
                                                }
                                                //printf("accept a clinent..[ip]:%s,[port]:%d\n",inet_ntoa(remote.sin_addr),ntohs(remote.sin_port));
                                                ep_ev.events = EPOLLIN|EPOLLET;
                                                ep_ev.data.fd = accept_sock;
                                                set_noblock(accept_sock);
                                                if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,accept_sock,&ep_ev)<0)
                                                {
                                                        perror("epoll_ctl");
                                                        close(accept_sock);
                                                }
                                                creattoclient(accept_sock);
                                        }else{
                                                if(ready_ev[i].events&EPOLLIN){
                                                        //申请空间同时存文件描述符合缓冲区地址
                                                	    memset(buf,'\0',sizeof(buf));
        	    										fflush(stdout);
                                                        ssize_t _s = recv(fd,buf,sizeof(buf)-1,0);
                                                        if (control_sock!=0)
                                                        {
                                                        	if(buf=="control:connect")
                                                        	control_sock = fd;
                                                        }else if(control_sock == fd){
                                                        	if (!strncasecmp(buf,"quit",4))
                                                        	{
                                                        		exit(0);
                                                        	}
                                                        }
                                                        if (_s<0)
                                                        {
                                                                perror("recv");
                                                                continue;
                                                        }else if(_s==0){
                                                        	    deletetoclient(fd);
                                                                epoll_ctl(epoll_fd,EPOLL_CTL_DEL,fd,NULL);
                                                                close(fd);
                                                        }else{
                                                        	    strcat(databuf,buf);
                                                                //printf("client#%s\n",buf);
                                                                recvstat = 1;
                                                                // ep_ev.data.fd = fd;
                                                                // ep_ev.events = EPOLLOUT|EPOLLET;
                                                                // epoll_ctl(epoll_fd,EPOLL_CTL_MOD,fd,&ep_ev);
                                                        }
                                                }else if(ready_ev[i].events&EPOLLOUT)
                                                {
                                                        //const char * msg = ".................";
                                                	if (databuf[0]!='\0')
                                                	{
                                                		send(fd,databuf,strlen(databuf),0);
                                                	}
                                                     //   epoll_ctl(epoll_fd,EPOLL_CTL_DEL,fd,NULL);
                                                     //   close(fd);
                                                }
                                        }
                                }
                        break;
                }
                if(recvstat == 1){
                	ep_ev.events = EPOLLOUT|EPOLLET;
                	for (int i = 0; i < CLIENT_NAMBER; ++i)
                	{
                		if(clientnum[i]==0){
                			continue;
                		}
                		ep_ev.data.fd = clientnum[i];
                        epoll_ctl(epoll_fd,EPOLL_CTL_MOD,clientnum[i],&ep_ev);
                	}
                }else if(recvstat == 0){
                	ep_ev.events = EPOLLIN|EPOLLET;
                	for (int i = 0; i < CLIENT_NAMBER; ++i)
                	{
                		if(clientnum[i]==0){
                			continue;
                		}
                		ep_ev.data.fd = clientnum[i];
                        epoll_ctl(epoll_fd,EPOLL_CTL_MOD,clientnum[i],&ep_ev);
                	}
                }
        }
}

int main(int argc,char *argv[])
{
	Server_Init();
	Epoll_Listen();
}
 

qt工程:

主线程.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H


#include <stdio.h>
#include <unistd.h>

#include <QMainWindow>
#include "conturlserver.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void addevent();

signals:
    void sendinfo(QString);
public slots:
    void showrecvtext(QString);

private:
    Ui::MainWindow *ui;
    conturlserver * sockthread;

};

#endif // MAINWINDOW_H

MainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    sockthread = new conturlserver;
    addevent();
}
void MainWindow::addevent(){
    connect(ui->start,&QPushButton::clicked,sockthread,&conturlserver::timejishi);
    connect(ui->stop,&QPushButton::clicked,[=](){
        if(sockthread->isRunning()){
            emit sendinfo("control:gameover");
        }
    });
    connect(this,&MainWindow::sendinfo,sockthread,&conturlserver::sendinfo);
    connect(ui->send,&QPushButton::clicked,[=](){
        QString str = ui->sendtext->text();
        emit sendinfo(str);
        ui->sendtext->setText("");
    });
    connect(sockthread,&conturlserver::recviinfor,this,&MainWindow::showrecvtext);
}

void MainWindow::showrecvtext(QString info){
    ui->recvtext->append(info);
}

MainWindow::~MainWindow()
{
    delete ui;
}

子线程conturlserver.h

#ifndef CONTURLSERVER_H
#define CONTURLSERVER_H

#include "QThread"
#include "QDebug"
#include "QTcpServer"
#include "QHostAddress"
#include "QTcpSocket"
#include "QTimer"

class conturlserver : public QThread
{
    Q_OBJECT
public:
    conturlserver();
    void run();

signals:
    void recviinfor(QString info);
public slots:
    void sendinfo(QString info);
    void timejishi();

private:
    QHostAddress myaddr;
    QTcpServer * mytcpfd;
    QTcpSocket * mysockfd;
    quint16 port = 6666;
    QTimer *timeout;
    QTimer *writetime;
    QByteArray recvdata;
    QByteArray senddata;
    bool sockstat;


};

#endif // CONTURLSERVER_H

子线程conturlserver.cpp

#include "conturlserver.h"

conturlserver::conturlserver()
{
    myaddr = "192.168.10.127";
    mysockfd = new QTcpSocket(this);

    writetime = new QTimer(this);
    connect(writetime,&QTimer::timeout,[=](){

    });
}

void conturlserver::run(){
    sockstat = false;
    if(mysockfd->ConnectedState == QAbstractSocket::UnconnectedState)
    {
        emit recviinfor("sockect is busying!!!\n");
        return;
    }
    while(1){
        if(mysockfd->isReadable()){
            recvdata = mysockfd->read(1024);
            if(!recvdata.isEmpty())
            emit recviinfor(recvdata.data());
            }
        sleep(1);
        }

}


void conturlserver::timejishi(){

        mysockfd->connectToHost(myaddr,port);
        if(mysockfd->waitForConnected())
        {
            mysockfd->write(QByteArray("control:connect"));
             this->start();
            emit recviinfor("sockect is connect success!!!\n");
        }else{
            emit recviinfor("sockect connecting is failder...\n");
            this->exit();
        }
}

void conturlserver::sendinfo(QString info){
    senddata = info.toLatin1();
    if(mysockfd->isWritable()){
        qint64 i = mysockfd->write(senddata);
        if(i>0){
           if(senddata=="control:gameover")
           {
               emit recviinfor("epoll_server quit !!!\n");
               this->exit();
           }
        }
    }else{
         emit recviinfor("send faile...\n");
    }
}

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最近在开发im服务器 需要大并发链接 QT默认的是使用select模型的 这种轮询方式非常慢 在高并发连接 我们需要epoll才能发挥linux服务器的性能 而且使用简单 整个服务端代码架构无需修改 直接可以使用 只要在 main文件添加: int main int argc char argv[] { #ifdef Q OS LINUX QCoreApplication::setEventDispatcher new EventDispatcherLibEvent ; qInstallMessageHandler customMessageHandler ; #endif QCoreApplication a argc argv ; auto ser new ConfigServer; ser >startServer ; return a exec ; } 在 pro文件添加 linux{ LIBS + levent core SOURCES + common eventdispatcher libevent eventdispatcher libevent cpp common eventdispatcher libevent eventdispatcher libevent config cpp common eventdispatcher libevent eventdispatcher libevent p cpp common eventdispatcher libevent socknot p cpp common eventdispatcher libevent tco eventfd cpp common eventdispatcher libevent tco pipe cpp common eventdispatcher libevent tco cpp common eventdispatcher libevent timers p cpp HEADERS + common eventdispatcher libevent common h common eventdispatcher libevent eventdispatcher libevent h common eventdispatcher libevent eventdispatcher libevent config h common eventdispatcher libevent eventdispatcher libevent config p h common eventdispatcher libevent eventdispatcher libevent p h common eventdispatcher libevent libevent2 emul h common eventdispatcher libevent qt4compat h common eventdispatcher libevent tco h common eventdispatcher libevent wsainit h } 可以直接跨平台了使用了 csdn博客:http: blog csdn net rushroom">最近在开发im服务器 需要大并发链接 QT默认的是使用select模型的 这种轮询方式非常慢 在高并发连接 我们需要epoll才能发挥linux服务器的性能 而且使用简单 整个服务端代码架构无需修改 直接可以使用 只要在 main文件添加: [更多]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值