客戶端註冊登陸,服務器匹配用戶名密碼
- 資源視圖建立對話框style->puptop,更改ID爲IDD_DIA_JOIN,添加基於CDialog類Sign_Join
- 添加兩個編輯框變量名分別是
m_edit1
和m_edit2
,然後添加按鈕,三個,功能分別是註冊,登陸,和退出 - 更改CDialog.h中的結構體和協議號的定義,相應的,在另一個程序裏Server.h文件中做同樣修改
enum{
//定義協議編號
INF_ADD = 0x1234,
INF_BROW,
INF_JOIN,
INF_LOGIN,
INF_FIND
};
struct ServerData
{
//信息數據
int Row;
int Column;
int Num;
char Account[200];
char Pass[200];
bool flag;
};
#include "afxwin.h"
- 設置登陸對話框的彈出位置,資源視圖,右邊屬性,重寫函數OnPaint()
void Sign_Join::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此處添加消息處理程序代碼
int xSize = ::GetSystemMetrics (SM_CXSCREEN);
int ySize = ::GetSystemMetrics (SM_CYSCREEN);
//設置窗口大小
int cx = (xSize*2)/6;
int cy = (ySize*3)/6;
//設置顯示位置
int x = (xSize-cx)/2;
int y = (ySize-cy)/2;
//設置主窗口位置和大小
CWnd::MoveWindow(CRect(x,y,cx+x,cy+y));
// 不爲繪圖消息調用 CDialog::OnPaint()
}
客戶端
- 一、客戶端中初始化及三個按鈕響應函數的實現,雙擊開啓函數
- 1、初始化,登陸註冊新建一個Socket進行與服務器的鏈接
- Sign_Join.h中,加一句
// Sign_Join 對話框
class Sign_Join : public CDialog
{
CSocket sock;
- 資源視圖下,登陸註冊對話框右邊屬性窗口,重寫函數OnInitDialog()
BOOL Sign_Join::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: 在此添加額外的初始化
SetWindowText("登陸/註冊");
//設置退出X禁用,不然點掉了直接跳出主程序窗口,登陸就無效了
::EnableMenuItem(::GetSystemMenu(this->m_hWnd, false), SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);//forbid close
sock.Create();
if (!sock.Connect("127.0.0.1",8668))//修改爲自己的IP
{
AfxMessageBox("連接失敗:無法連接服務器,請檢查你的網絡連接!");
EndDialog(IDCANCEL);
return FALSE;
}
return TRUE; // return TRUE unless you set the focus to a control
// 異常: OCX 屬性頁應返回 FALSE
}
- 2、註冊按鈕的函數響應,都在Sign_Join.cpp文件中
void Sign_Join::OnBnClickedButton1()
{
// TODO: 在此添加控件通知處理程序代碼
CString m_Sign_Account,m_Sign_Pass;
m_edit1.GetWindowText(m_Sign_Account);
m_edit2.GetWindowText(m_Sign_Pass);
//檢查輸入是否爲空,去除左右空格
m_Sign_Account.TrimLeft();
m_Sign_Account.TrimRight();
m_Sign_Pass.TrimLeft();
m_Sign_Pass.TrimRight();
if((m_Sign_Account=="")||(m_Sign_Pass==""))
{
AfxMessageBox("error");
return;
}
int nCmd1 = INF_JOIN; //發送給服務器的命令
sock.Send(&nCmd1,sizeof(nCmd1));
//類型轉換,發送的信息不能爲CString格式,轉化爲用戶名和密碼的Char類型,並且flag真,表示已經存在,(假爲不存在,剛註冊)
ServerData data;
strncpy(data.Account,(LPCTSTR)m_Sign_Account,sizeof(data.Account));
strncpy(data.Pass,(LPCTSTR)m_Sign_Pass,sizeof(data.Pass));
data.flag=true;
sock.Send(&data,sizeof(data));
//從服務器接收被處理過的data,驗證flag
sock.Receive(&data,sizeof(data));
if(!data.flag)
{
AfxMessageBox("註冊成功");
//CDialog::OnOK();
}
else
{
AfxMessageBox("用戶已存在");//用戶已存在提示框,不關閉註冊框,可讓用戶自由選擇是否繼續註冊
}
}
3、登陸按鈕
void Sign_Join::OnBnClickedButton2()
{
// TODO: 在此添加控件通知處理程序代碼
CString m_Login_Account,m_Login_Pass;
m_edit1.GetWindowText(m_Login_Account);
m_edit2.GetWindowText(m_Login_Pass);
m_Login_Account.TrimLeft();
m_Login_Account.TrimRight();
m_Login_Pass.TrimLeft();
m_Login_Pass.TrimRight();
if((m_Login_Account=="")||(m_Login_Pass==""))
{
AfxMessageBox("error");
return;
}
int nCmd2 = INF_LOGIN;
sock.Send(&nCmd2,sizeof(nCmd2));
ServerData data;
strncpy(data.Account,(LPCTSTR)m_Login_Account,sizeof(data.Account));
strncpy(data.Pass,(LPCTSTR)m_Login_Pass,sizeof(data.Pass));
data.flag=false;
sock.Send(&data,sizeof(data));
sock.Receive(&data,sizeof(data));
if(data.flag)
{
AfxMessageBox(m_Login_Account+" "+" "+"成功登錄");//找到則顯示的是用戶名+性別+已登錄
m_Login_Account="";//成功登錄後把用戶框和密碼框文本清除
m_Login_Pass="";
//UpdateData(FALSE);//將數據從控件變量傳遞給控件
pDlg->turnf();
OnOK();
}
else{
MessageBox("用戶名不存在或密碼錯誤");//用戶密碼錯誤或用戶不存在提示
}
}
4、退出按鈕,直接退出程序
void Sign_Join::OnBnClickedCancel()
{
// TODO: 在此添加控件通知處理程序代碼
exit(0);
//OnCancel();
}
- 5、設置禁止移動對話框,資源視圖,點擊登陸對話框,屬性添加消息響應WM_SYSCOMMAND,注意最後是CDialog::,不管是什麼類都是這個
void Sign_Join::OnSysCommand(UINT nID, LPARAM lParam)
{
// TODO: 在此添加消息處理程序代碼和/或調用默認值
if (nID == SC_MOVE || nID==0xF012)
return;
else
CDialog::OnSysCommand(nID, lParam);
}
服務器
- 二、在服務器的ClientSocket.cpp文件中,被重載的虛函數OnReceive中寫入協議命令的函數。
void CCLientSocket::OnReceive(int nErrorCode)
{
// TODO: 在此添加專用代碼和/或調用基類
int nCmd = 0,nLen = 0;
if(Receive(&nCmd,sizeof(nCmd))<=0)
return ;
switch(nCmd)
{
case INF_ADD:
AddData();
break;
case INF_BROW:
Browse();
break;
case INF_JOIN:
join_add();
break;
case INF_LOGIN:
login_find();
break;
}
CSocket::OnReceive(nErrorCode);
}
1、join_add()函數的具體實現
void CCLientSocket::join_add(void)
{
ServerData data;
Receive(&data,sizeof(data));
//return ;
CString m_Sign_Account(data.Account);
CString m_Sign_Pass(data.Pass);
//m_Sign_Account(data.Account);
//m_Sign_Pass(data.Pass);
// TODO: 在此添加控件通知處理程序代碼
CString username;//從文件中讀取用戶名進行校驗,如果輸入的用戶名在文件已存在則不進行註冊
bool flag=false;//標記
char * path="username.txt";//文件路徑
CFile fp;//使用MFC的CFile將暑假寫入文件
fp.Open((LPCTSTR)path,CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite);
fp.SeekToBegin();//移動文件指針位置至文件頭
CArchive ar(&fp,CArchive::load);//使用CArchive進行讀取文件
//校驗操作
while(ar.ReadString(username))
{
username.TrimLeft();
username.TrimRight();
if(strcmp(username,m_Sign_Account)==0) {
flag=true;//如果已存在用戶名,則標記flag爲true
break;
}
else {
ar.ReadString(username);//讀取下一行(每一行爲一個屬性,比如用戶名,密碼,性別,總共3 個屬性)
ar.ReadString(username);//讀取下一
}
}
ar.Close();
fp.SeekToEnd(); //文件寫入爲追加操作,所以寫入前必須將文件指針移動至文件尾
if(!flag)
{
//CFile Write(*str,GetLength())寫入
fp.Write(m_Sign_Account,m_Sign_Account.GetLength());
//win雖是\r\n,在寫程序只需要\n即可換行
fp.Write("\n",sizeof(char));
fp.Write(m_Sign_Pass,m_Sign_Pass.GetLength());
fp.Write("\n",sizeof(char));
fp.Close();
data.flag=false;
}
Send(&data,sizeof(data));
}
- 2、login_find()函數的實現
void CCLientSocket::login_find(void)
{
ServerData data;
Receive(&data,sizeof(data));
CString m_Login_Account(data.Account);
CString m_Login_Pass(data.Pass);
CString username;
CString password;
//與註冊類似操作
bool flag=false;
char * path="username.txt";
CFile file;
file.Open(path,CFile::modeRead);
file.SeekToBegin();
CArchive ar(&file,CArchive::load);
//去除數據左右空格數據
//校驗用戶密碼,與註冊校驗相同的操作,這裏多驗證了一步,即校驗密碼
while(ar.ReadString(username))
{
if(ar.ReadString(password))
{
username.TrimLeft();
username.TrimRight();
password.TrimLeft();
password.TrimRight();
if(strcmp(username,m_Login_Account)==0
&&strcmp(password,m_Login_Pass)==0)
{
flag=true;
data.flag=true;
//ar.ReadString(sex);//如果用戶驗證正確,flag=true,並且sex爲用戶的性別
break;
}
}
//ar.ReadString(sex);
}
//關閉CFile和CArchive
Send(&data,sizeof(data));
ar.Close();
file.Close();
}