Linux下基于EPOLL 模型,实现用户登录,客户端采用QT
来源:互联网 发布:程序员适合写那些博客 编辑:程序博客网 时间:2024/05/16 04:00
只实现的最基本的功能框架,仅供参考。
服务端
首先定义了一个结构体:
#define NAME_AND_PASSWD_SIZE 31typedef struct login_message { char usr_name[NAME_AND_PASSWD_SIZE+1]; char usr_passwd[NAME_AND_PASSWD_SIZE+1]; }l_msg;
一个消息标识:
# define LOGIN_MSG 0x0001
先实现客户端的主体框架
对于一个简单的服务器模型,直接照搬下面的代码即可,对于其中的每一个连接,传给相应的连接处理函数。
<pre name="code" class="cpp">#include <stdio.h> #include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <unistd.h>#include <netinet/in.h>#include <errno.h>#include <sys/epoll.h>#include <fcntl.h>#define PORT 6666#define LISTEN_QUEUE 5#define MAXBUF 1024#define MAXEPOLL_SIZE 10000#define MAX_EVENT 10void set_socket_non_blocking( int sockfd);// 设置为非阻塞int main(){int listenfd, connfd, nfds, epollfd, n;struct sockaddr_in server_addr, client_addr;struct epoll_event ev, events[MAX_EVENT];socklen_t server_len = sizeof(server_addr);socklen_t client_len = sizeof(server_addr);if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) <0){perror("init:");exit(1);}server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(PORT);server_addr.sin_family = AF_INET;if (bind(listenfd, (struct sockaddr *)&server_addr, server_len) <0){perror("bind:");exit(1);}if (listen(listenfd, LISTEN_QUEUE) < 0){perror("listen:");exit(1);}printf("listenning ...\n");if((epollfd = epoll_create(MAXEPOLL_SIZE)) < 0){perror("epoll create:");exit(1);}ev.events = EPOLLIN;ev.data.fd = listenfd; if( epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev) <0){perror("epoll_ctl:");exit(1);}while(1){if((nfds = epoll_wait(epollfd, events, MAX_EVENT, -1)) <0){perror("epoll_wait:");exit(1);}for (n = 0; n < nfds; ++n){if(events[n].data.fd == listenfd){if((connfd = accept(listenfd, (struct sockaddr*)&client_addr, &client_len)) < 0){perror("accept:");exit(1);}set_socket_non_blocking(connfd);ev.events = EPOLLIN | EPOLLET;ev.data.fd = connfd;if( epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &ev) ==-1){perror("epoll_ctl:connfd");exit(1);}} else str_handle(events[n].data.fd);}}return 0;}void set_socket_non_blocking( int sockfd ){int ret;ret = fcntl( sockfd, F_GETFL );if ( ret < 0 ){perror("fcntl get");exit(1);}ret = ret|O_NONBLOCK;if( fcntl( sockfd, F_SETFL, ret)<0){perror("fcntl set");exit(1);}}
对于每一个连接,即调用 str_handle()函数进行处理。
str_handle() 的函数原型如下:
void str_handle(int connfd ){l_msg msg;// 定义一个登录消息的的结构体变量char buffer[BUFF_SIZE] ;uint16_t msg_id;memset( buffer, 0, BUFF_SIZE);uint16_t login_tag = 0; //是否登录成功,默认0表示登录失败read( connfd, buffer , BUFF_SIZE);memcpy( &msg_id, buffer, sizeof(uint16_t));switch (msg_id){case LOGIN_MSG:memcpy(&msg, buffer + 2, sizeof(l_msg));printf("usr_name: %s\n", msg.usr_name);printf("passwd: %s\n", msg.usr_passwd);login_tag = login_check( msg );write( connfd, &login_tag, sizeof(uint16_t));//break;default:break;}}
1、首先先从缓冲区中拷贝1024个字节进buffer数组
2、因为客户端的请求头为 uint16_t msg_id + l_msg(即一开始定义的结构体数组)
3、拷贝两个字节对msg_id进行赋值,用于判断是一个什么样的消息,然后采用switch函数对消息类型进行控制。
4、如果是登录消息,则给结构体变量msg赋值,并传递给函数login_check()进行数据库查询,返回值用于确定是否登录成功,返回0表示查询失败,返回1表示查询成功
5、将是否登录成功的消息发送给客户端
下面是login_check 的函数原型
int login_check( l_msg msg){int flag;MYSQL mysql; //声明mysql变量mysql_init(&mysql);//初始化mysqlif(!mysql_real_connect(&mysql,"localhost","root","123456","practise",3306,NULL,0)){printf("Error connecting to Mysql!\n");}else{printf("Connected Mysql successful!\n");}char sql[256] = {0};char *sql1 = "select '";char *sql2 = "' from account where password =";char *sql3 = ";";strcat( sql, sql1);strcat( sql, msg.usr_name );strcat( sql, sql2);strcat( sql, msg.usr_passwd );strcat( sql, sql3);flag = mysql_real_query(&mysql, sql, (unsigned int)strlen(sql)); //该函数对数据库进行查询,返回是否成功的进行了查询if(flag)//若未成功查询,返回0{printf("Query failed!\n");return 0;}else{printf("[%s] made ...\n",sql);}MYSQL_RES *result =mysql_store_result(&mysql); //*result 指向结果集if ( mysql_num_rows(result) == 0 ) //取出结果集,若结果集为空证明无此用户,返回0{mysql_free_result(result);return 0;}mysql_free_result(result); //释放结果集return 1;//若有此用户返回1}
数据库的连接方式采用包含头文件,以及链接的时候链接mysql客户端的接口库
我的头文件
#include <mysql/mysql.h>
gcc 编译时采用如下命令:
gcc server.o str_handle.o -o server -L /usr/lib/mysql -lmysqlclient
贴下我自己写的makefile文件吧,程序代码没有进行规划,仅供参考。
server: server.o str_handle.o gcc server.o str_handle.o -o server -L /usr/lib/mysql -lmysqlclientserver.o: server2.c gcc -c -g server.cstr_handle.o: str_handle.c str_handle.h data_form.hgcc -c -g str_handle.c
qt端
main函数:
#include "send_file.h"#include "logindlg.h"#include <QApplication>#include <QTextCodec>char usr_name[32];int main(int argc, char *argv[]){ QApplication a(argc, argv); Send_file w; LoginDlg l; if ( l.exec()==QDialog::Accepted) { w.show(); return a.exec(); }}
LoginDlg 类头文件
#ifndef LOGINDLG_H#define LOGINDLG_H#include <QDialog>#include <QtNetwork>#include "data_form.h"namespace Ui {class LoginDlg;}class LoginDlg : public QDialog{ Q_OBJECTpublic: explicit LoginDlg(QWidget *parent = 0); ~LoginDlg();private slots: void on_login_btn_clicked(); void new_conn(); void read_msg(); void display_error(QAbstractSocket::SocketError); void write_msg();private: Ui::LoginDlg *ui; QTcpSocket *tcpsocket; char buffer[BUFF_SIZE]; //quint16 block_size; int flag; uint16_t login_tag;};#endif // LOGINDLG_H
LoginDlg类 cpp文件
#include "logindlg.h"#include "ui_logindlg.h"#include "data_form.h"#include <QMessageBox>extern char usr_name[32];LoginDlg::LoginDlg(QWidget *parent) : QDialog(parent), ui(new Ui::LoginDlg){ ui->setupUi(this); tcpsocket = new QTcpSocket(this); ui->passwd_edit->setEchoMode(QLineEdit::Password); connect(tcpsocket, SIGNAL(readyRead()), this, SLOT(read_msg())); connect(tcpsocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(display_error(QAbstractSocket::SocketError)));}LoginDlg::~LoginDlg(){ delete ui;}void LoginDlg::on_login_btn_clicked() //按下登录按钮时调用该槽函数{ new_conn(); write_msg();}void LoginDlg::new_conn() //新建连接{ //block_size = 0; tcpsocket->abort();//cancel the connected tcpsocket->connectToHost("127.0.0.1",6666);}void LoginDlg::read_msg(){ memset(buffer, 0, BUFF_SIZE); tcpsocket->read( buffer, BUFF_SIZE ); memcpy(&login_tag, buffer, sizeof(uint16_t)); if(login_tag == 1) { accept(); } else { QMessageBox::warning(this,tr("Warning"),tr("user name or password error!"),QMessageBox::Yes); }}void LoginDlg::display_error(QAbstractSocket::SocketError){ qDebug() << tcpsocket->errorString();//output the error message}void LoginDlg::write_msg() //发送用户名、密码{ l_msg msg; uint16_t msg_id = LOGIN_ID; int name_len = ui->usrname_edit->text().length(); int pass_len = ui->passwd_edit->text().length(); memcpy( msg.usr_name, ui->usrname_edit->text().toStdString().c_str(), name_len); msg.usr_name[name_len] = '\0'; memcpy( msg.usr_passwd, ui->passwd_edit->text().toStdString().c_str(), pass_len); msg.usr_passwd[pass_len] = '\0'; strcpy(usr_name, msg.usr_name); memset( buffer, 0, BUFF_SIZE); memcpy( buffer, &msg_id, 2); memcpy( buffer+2, &msg ,sizeof( msg)); tcpsocket->write( buffer, 2+sizeof(msg));}
data_form.h
#ifndef DATA_FORM_H#define DATA_FORM_H#include <stdint.h>//消息信号const int LOGIN_ID = 0x0001;//常量大小 const int BUFF_SIZE = 1024; const int MAX_CLIENT 20;const int NAME_AND_PASSWD_SIZE 31typedef struct login_message { char usr_name[NAME_AND_PASSWD_SIZE+1]; char usr_passwd[NAME_AND_PASSWD_SIZE+1]; }l_msg; #endif
0 0
- Linux下基于EPOLL 模型,实现用户登录,客户端采用QT
- Linux 下Epoll模型
- 采用epoll模型服务器连接管理器实现
- 基于linux下的epoll服务端和客户端编程实例
- linux下epoll模型程序
- 基于Linux epoll模型的Simple
- linux环境下基于UDP的 客户端服务器模型
- Linux下的socket编程-基于Qt的客户端
- QT实现用户登录功能
- 【Qt编程】基于Qt的词典开发系列<八>--用户登录及API调用的实现
- Linux下EPoll通信模型简析
- Linux下EPoll通信模型简析
- Linux下EPoll通信模型简析
- linux下epoll模型accept并发问题
- linux下epoll模型应用介绍
- Linux下epoll网络编程模型
- Linux下EPoll通信模型简析
- Linux下EPoll通信模型简析
- 3个点的action button 不显示问题
- Linux下套接字编程简例
- Ultimaker2 3D打印机源文件在线公布
- android4.2源代码编译环境搭建
- Arduino舵机控制1
- Linux下基于EPOLL 模型,实现用户登录,客户端采用QT
- maven学习总结初步
- rpm,yum和apt使用详解
- 2014 Shenzhen Maker Faire见闻
- ZOJ 1007 Numerical Summation of a Series (数学)
- Js实现动态添加删除Table行
- android控件RatingBar改变大小
- 浅谈Android系统开发中一些概念的理解
- 有效控制Android应用程序的耗电量