
1 团队介绍
团队组成:
齐爽爽(258)个人博客:http://www.cnblogs.com/shuangshuangblog/
马帅(248)个人博客:http://www.cnblogs.com/whu-mashuai/
何健(267)个人博客:http://www.cnblogs.com/hankin2017/
蔡凯峰(285)个人博客:http://www.cnblogs.com/cai2017282110285/
团队Git链接:https://github.com/WHUSE2017/C-team
2 Bate过程回顾
2.1 团队项目目标
(1)预期典型用户:18--40岁在武汉的人,前期只在武汉大学,武大学生。
(2)预期功能描述:能够发布自己的活动行程、搜索到某时间某地点的活动及参加人员信息。
(3)预期用户数量:前期500人左右。
2.2 如何满足用户需求
只要是本系统的用户,我们都提供活动查询,不过是一件想好取得地点,或者没有想好干什么,但是有时间,都能在系统里面找到想要的信息,即使当时没有找到,你也可以自己做主,发布行程消息,等待其他人的加入。至少我们提供一个集中的平台,更易于找到想找到的人。
像正常软件一样,用户登录自己的账户,可以直接查看自己的活动行程,也可以点击取消自己的活动,当然,用户最好给系统一个反馈,好让系统的信息更准确。
2.3 分工与经验教训
我们分工依然比较粗暴的,
前台界面:何健;
逻辑层:蔡凯峰;
数据库设计与连接以及Alpha版展示与讲解:马帅;
文档编辑与组员协作:齐爽爽。
经验教训:
(1)面对面沟通:依然是加强沟通。因为这个周末,大家都有事情,所以小组会议移交在网上,还是没有面对面来的实在。
(2)还想用《构建之法》里面的那段:>scrum计划阶段的估计不是一个"合同",领导们不要把它当成一个合同。估计总是不准的。坚持短期的sprint,这样即使不准的估计也不会又打的损害。真的觉得敏捷的sprint还是很有效的。
2.4 项目管理
项目管理就是按照老师上课讲的和书上讲的大概中和一下,分工明确,各自领取任务,然后每天汇报。然后具体修改文档发到讨论组。
2.5 如何做到如期交付
有计划。主要在前期老师给了两周时间来做分析,把思路计划都已经做好了,所以在冲刺阶段,基本按照前期计划走,有一个计划在那里,所以每天看着燃尽图都有种“革命尚未成功,同志仍需努力”的紧迫感。
还有小组成员也都很负责。虽然老师任务也很重,但是能熬夜做项目,即使最后交付的东西还不够完善,但是至少能做到,既然咱们干这个事情,就要负责,在规定时间完成自己的任务。
3 燃尽图
在上次,是木真正的会使用leangoo,后期修改了时间,所以会有偏差,这次一开始就设置好了所有参数,所以还很很准确的显示了项目完成度,因为全部都没有在计划内完成..........于是在最后一天疯狂的解决问题。
4 留给后面小组的说明
项目文件:
文件说明:
1.SQLStruct.h
定义了与数据库操作相关的一些结构体:
struct userStruct; //用户信息
struct EventStruct; //事件信息
struct StationMessageStruct; //站内信
struct ParticipantsStrcut; //事件参与
struct SecretSecurityStruct; //密保
1
2.Operate.h/Operate.cpp
与数据库进行交互的类,类的定义如下:
class Operate {
public:
Operate(); string IntToString(int variable);
int StringToInt(string variable); bool InsertIntoUserTable(userStruct User);
bool InsertIntoEventTable(EventStruct Event);
bool InsertIntoStationMessageable(StationMessageStruct StationMessage);
bool UpdateUserTable(userStruct User);//修改用户信息
bool UpdatePassword(string UserName, string Password); //修改密码
bool InsertIntoSecretSecurity(SecretSecurityStruct Security); //添加密保
bool joinEvent(int EventID, string username); //加入活动
bool setEventState(int Eventid, int State);//设置活动状态
SecretSecurityStruct GetSecretSecurity(string UserName); //获取密保 bool DeleteDataParticipants(int EventID, string UserName);//删除Participants中特定数据 vector<userStruct> LikeUserName(string username);//模糊查找用户名 vector<ParticipantsStrcut> GetParticipantsByUsername(string Username);
vector<EventStruct> getEventByCondition(string publisher, string participant, int state);
//查看已发布,或已加入的活动
string GetPasswordFromUserTable(string username);
userStruct GetUserDetails(string username); //获取用户信息
vector<EventStruct> GetEvent(string StartSite, string EndSite, string StartTime, string EventType); //搜索活动信息
vector<EventStruct> GetEventByState(int State);//通过活动状态查询活动
vector<EventStruct> GetEventByLike(string StartSite, string EndSite);//开始地和结束地模糊查询
vector<string> GetParticipants(int EventId);//获取活动的参与者 vector<StationMessageStruct> GetMessageBySender(string SenderName);
vector<StationMessageStruct> GetMessageByReceiver(string ReceiverName);
EventStruct GetEventDetailById(int EventId);
public:
MYSQL mydata;
};
2
3.socket_stream.h/socket_stream.cpp
处理socket流数据的类,定义如下:
class socket_stream{
public:
enum
{
disconnected,
connected,
}; //用来判断socket状态的enum值
socket_stream(char *ip,unsigned short port); //客户端构造函数,指定要连接 //的远程主机的ip,port
socket_stream(SOCKET s,sockaddr_in * lpremoteAddr = NULL,int nAddrlen=);
//服务端构造函数,将监听到的socket连接传进来,剩下的两个参数
//可以用来获取socket连接的其他信息
~socket_stream(); //析构函数,有些东西需要在这释放掉
int recvData(char *buffer, int buflen, int flag =); //接收流数据
int sendData(char *buffer, int buflen, int flag =); //发送流数据
int getState(); //获取当前连接的状态
private:
void init_cs(); //CRITICAL_SECTION初始化CRITICAL_SECTION结构
SOCKET sock;
int state;
CRITICAL_SECTION send_cs; //这两个变量用来锁住对读写缓冲区的操作,避免多个线程同时
CRITICAL_SECTION recv_cs; //操作同一个socket连接的读写缓冲区
sockaddr_in remoteAddr;
int nAddrlen;
};
3
4.socket_packet.h/socket_packet.cpp
将socket流数据封装成packet。
enum
{
PACKET_LOGIN,
PACKET_GETXX,
PACKET_SETXX,
}; #pragma pack (push,1) /*指定1字节对齐,有些编译器会补齐成4字节对齐,需要指定1字节对 齐,否则底层缓冲区可能对数据的长度判断出错*/
typedef struct {
unsigned int type; //packet类型
unsigned int length; //整个packet的长度
unsigned int flag; //附加的标志
char data[]; //数据
}packet_t;
#pragma pack (pop) /*还原默认字节对齐*/ class socket_packet
{
public:
enum
{
err_stream_check,
err_stream_state=-,
}; //在这一层出错时返回的错误标志
socket_packet(socket_stream *stream); //构造
~socket_packet(); //析构,释放相应内存
int send_packet(packet_t *packet,int length); //发送一个packet
int recv_packet(); //接收一个完整的packet,返回接收的标志
char *get_buffer(); //接收成功后,用该函数获取packet数据
private:
bool check_buffer(packet_t *p); //检查本类中申请的buffer是否足够大,不足将继续申请 //内存
socket_stream *mStream; //封装在该层的底层类
char *buffer; //可变长的缓冲区
int bufLength; //缓冲区长度
};
4
5.session_s.h/session_s.cpp
一个session的服务端代码,用来获取用户请求和发送处理结果
class session_s
{
public:
enum {
disconected,
have_request,
}; //判断session的状态
session_s(socket_packet *sp); //构造
~session_s(); //析构
bool login(char *username,char*pass);
bool _register(void *p);
int wait_request(); //等待用户请求
request_t *get_request(); //获取用户请求
bool send_reply(reply_t *reply); //发送回复
void login_success(char* name); //登录成功后设置相关标志
bool IsLogin(){return this->b_login;} //判断当前用户是否已经登录
void setSqlOperate(Operate * o){op=o;} //设置数据库操作类
char* getusername(){return username;} //登录成功后可用来获取当前用户名
Operate *op;
private:
bool b_login;
char username[];
socket_packet *sp;
request_t request;
char *reply_buffer;
char reply_buffer_len;
};
5
6.session_c.h/session_c.cpp
一个session的客户端代码,用来生成、发送用户请求,接收处理结果
class session_c
{
public:
enum {
disconected=-,
have_request=,
}; //session状态
session_c(socket_packet *sp);
~session_c();
bool login(char *params);
bool _register(char* params);
struct userStruct getUserInfo(char *params);
int wait_reply(); //等待服务端回复
reply_t *get_reply(); //获取回复结果
bool SendAndCheck(request_t *req); //发送requeset并检查当前状态,等待回复
int getState(){return this->state;}; //获取当前session状态
bool addEvent(char* params); //添加活动
vector<StationMessageStruct> getStationMessage();//获取站内信
bool addMessage(char *params); //发送消息
vector<EventStruct> getEvent(char* params); //出发地,目的地,时间,活动类型获取活动
bool joinEvent(char * params); //参加某个活动
vector<string> getParticipants(char* params); //获取某个活动的所有参与者
EventStruct getEventByID(char* params); //获取某一个活动
bool updatauserinfo(char* params); //修改用户信息
bool exitEvent(char *params); //退出某个活动
bool setEventState(char *parmas); //设置活动的状态,进行中,完成,取消
vector<EventStruct> getEventByConditions(char* params);//获取已发布或已加入的活动
bool setSecurity(char* params); //设置密保
string getSecurity(char *params); //获取密保问题
string checkSecurity(char *params); //检查密保回答是否正确,返回密码
private:
int send_request(request_t *req); //发送请求
int state; //当前session状态
socket_packet *sp; //封装的packet处理类
bool b_login;
reply_t reply;
char *buffer;
int bufferlen;
};
7.request_reply.h
以上两个session类中所需的一些定义:
enum
{
TYPE_LOGIN,
TYPE_REGISTER,
TYPE_GETUSERINFO,
TYPE_ADDEVENT,
TYPE_GETMESSAGE,
TYPE_ADDMESSAGE,
TYPE_GETEVENT,
TYPE_JOINEVENT,
TYPE_GETPARTICIPANTS,
TYPE_GETEVENTDETAILBYID,
TYPE_UPDATEUSERINFO,
TYPE_EXITEVENT,
TYPE_SETEVENTSTATE,
TYPE_GETEVENTBYCONDITIONS,
TYPE_SETSECURITY,
TYPE_GETSECURITY,
TYPE_CHECKSECURITY
};
typedef struct{
int type;
int flag;
int datalen;
char *data;
}request_t; typedef struct{
int type;
int flag;
int datalen;
char *data;
}reply_t;
7
8.UserClient.h/UserClient.cpp
提供给客户端界面的接口类
class UserClient
{
public:
UserClient(char *ip, unsigned short port); //连接服务端的ip,port
bool Login(char *name,char* password); //登录
bool Register(struct userStruct userInfo); //注册
int getState(){return this->state;}; //获取session状态
bool reConnect(); //重连
bool fisrtConnect(); //第一次连接
struct userStruct getUserInfo(char* username); //获取用户信息
bool addEvent(EventStruct Event); //发布活动
bool sendMessage(StationMessageStruct message); //发送消息
vector<StationMessageStruct> getStationMessage(); //获取站内信
vector<EventStruct> getEvent(string StartSite, string EndSite, string StartTime,string EventType);
//获取活动列表
bool joinEvent(int EventID, string username); //加入活动
vector<string> getParticipants(int EventID); //获取参与者列表
EventStruct getEventById(int EventID); //获取活动详情
void Logout(); //注销当前用户
bool UpdateUserInfo(struct userStruct userInfo); //修改用户信息
bool ExitEvent(int EventID,string username); //退出活动
bool SetEventState(int EventID,int state); //设置活动状态
vector<EventStruct> getEventByConditions(string publisher,string participant,int state);
//获取已发布或已加入的活动
bool SetSecurity(string username,string sercurity,string answer);
//设置密保
string GetSecurity(string username);
//获取密保问题
string CheckSecurity(string username,string security,string answer);
//检查密保回答是否正确,如果正确返回密码
//服务端会返回密码
private:
int state;
session_c* sc; //封装的session类
char mIp[];
unsigned short mPort;
char *buffer;
int bufferlen;
};
9.Service.h/Service.cpp
服务端服务代码
class Service
{
public:
enum{
failed,
success,
}; //当前服务状态
Service(unsigned short port); //构造要监听的端口
~Service(); //析构
int get_state(){return state;}; //获取当前服务状态
void start_loop(); //开始循环,等待连接
void setSqlOperate(Operate *o){op=o;} //设置数据库操作类
Operate *getSqlOperate(){return op;}; //获取数据库操作类
private:
Operate *op;
socket_packet *sp;
int state;
SOCKET slisten;
void new_connect_handler(SOCKET); //每一个新连接都会生成一个新线程处理
};
10.serverthread.h
处理每个连接的线程逻辑代码
DWORD WINAPI myServerThread(LPVOID lpParam)
{ /*每一个连接都会有一个这样的处理线程*/
ServerThreadParam *lp =(ServerThreadParam*)lpParam;
session_s *s = lp->session;
while()
{
int state = s->wait_request();
if (state == s->disconected)
break;
request_t * req = s->get_request(); //获取请求
//根据不同的请求类型,调用不同的处理逻辑(service_xxx)。
switch(req->type)
{
case (TYPE_LOGIN):
{
service_login(s,req);
break;
}
case(TYPE_REGISTER):
{
service_register(s,req);
break;
}
case(TYPE_GETUSERINFO):
{
service_getuserinfo(s,req);
break;
}
case(TYPE_ADDEVENT):
{
service_addevent(s,req);
break;
}
case(TYPE_GETMESSAGE):
{
service_getmessages(s,req);
break;
}
case(TYPE_ADDMESSAGE):
{
service_addmessage(s,req);
break;
}
case(TYPE_GETEVENT):
{
service_getevent(s,req);
break;
}
case(TYPE_JOINEVENT):
{
service_joinevent(s,req);
break;
}
case(TYPE_GETPARTICIPANTS):
{
service_getparticipants(s,req);
break;
}
case(TYPE_GETEVENTDETAILBYID):
{
service_geteventdetail(s,req);
break;
}
case(TYPE_UPDATEUSERINFO):
{
service_updateuserinfo(s,req);
break;
}
case(TYPE_EXITEVENT):
{
service_exitevent(s,req);
break;
}
case(TYPE_SETEVENTSTATE):
{
service_seteventstate(s,req);
break;
}
case(TYPE_GETEVENTBYCONDITIONS):
{
service_geteventbycondition(s,req);
break;
}
case(TYPE_SETSECURITY):
{
service_setsecurity(s,req);
break;
}
default:
break;
}
}
return ;
}