操作系統與網絡 2019-4-17

1.Author 端

1.1 新建一個基於對話框的MFC應用程序

  • 1.使用寬字符集;
  • 2.將之前寫的 Net 中的文件與 Kernel 中的文件拷貝過來;
  • 3.添加兩個篩選器;
  • 4.在添加的兩個 TCPKernel.cpp 與 TCPNet.cpp 文件頭添加上 stdafx.h 的引用,不然運行程序會出錯;
  • 5.給項目添加 附加包含目錄 ,將 Net Kernel 以及 PackDef 的路徑添加進去;

1.2 修改 TCPNet 下的東西

  • 1.由於我們在客戶端,不需要進行監聽,不需要進行bind,因此需要修改相關的 TCPNet.cpp 中的 InitNetWork 函數;
  • 2.定義本機的IP地址爲宏: SERVER_IP “192.168.3.25” ;
  • 3.更改類中的變量名,將 m_sockListen 更改爲 m_sock_client ;
  • 4.因爲不需要監聽,因此我們綁定好本機地址信息後直接進行連接: connect ;
  • 5.連接成功創建收數據的線程: ThreadRecv ;
bool TCPNet::InitNetWork()
{
	//1.選擇種類 -- 
	WORD wVersionRequested;
    WSADATA wsaData;
    int err;

/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        /* Tell the user that we could not find a usable */
        /* Winsock DLL.                                  */
       // printf("WSAStartup failed with error: %d\n", err);
        return false;
    }


    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
       // printf("Could not find a usable version of Winsock.dll\n");
        UnInitNetWork();
        return false;
    }

	//2.僱傭店長 -- socket 
	m_sock_client = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP );
	if(m_sock_client == INVALID_SOCKET )
	{
		UnInitNetWork();
		 return false;
	}
	//3.選址 --- 
	sockaddr_in  addrServer;
	addrServer.sin_family = AF_INET;
	addrServer.sin_addr.S_un.S_addr = inet_addr(SERVER_IP);
	addrServer.sin_port = htons(_DEFPORT);
	if(SOCKET_ERROR ==connect(m_sock_client,(const sockaddr*)&addrServer,sizeof(addrServer)))
	{
		 UnInitNetWork();
		 return false;
	}
	
	//5.創建線程
	m_hThreadRecv = (HANDLE)_beginthreadex(NULL,0,&ThreadRecv,this,0,0);
	
	return true;
}

1.3 更改參數

  • 1.TCONet 中的 SendData 函數,在 Server 端需要一個套接字來區分向哪個客戶端發送數據,但是在客戶端中,與服務器連接的和與服務器進行數據交換的使用的是同一個套接字,因此不需要一個新的套接字作爲參數傳入;
  • 2.TCPKernel 中的 DealData 函數因爲只有本客戶端一個套接字,因此不需要將套接字作爲參數傳入;

1.4 刪除多餘代碼

  • 1.將卸載中的相關不需要的代碼刪除(與鏈表相關的,客戶端中不需要鏈表);
  • 2.刪除 ThreadAccept 線程處理函數;

1.5 更改Kernel類

  • 1.首先更改 IKernel.h ,其中的 DealData 函數,不需要 SOCKET 參數,因爲都是從服務器端發送過來的數據;
  • 2.添加一個發送數據的接口: bool SendData(char* szbuf, int nlen)=0 ;
  • 3.刪除 TCPKernel 裏與 MySQL 和 ThreadPool 相關的代碼;
  • 4.在 Open 函數中只需要初始化網絡即可;在 Close 函數中卸載網絡;
  • 5.將 TCPKernel.h 中的函數指針去掉 SOCKET 參數;
  • 6.完成 SendData 函數,就是用網絡對象調用網絡的 SendData 函數;

1.6 在窗口上連接服務器

  • 1.在 app 類中添加一個 IKernel 類型的指針對象,在構造裏 new 一個 TCPKernel ;
  • 2.重寫一個 ExitInstance 函數,在裏面 delete 指針對象;
  • 3.在 主對話框類 中顯示主對話框之前 連接服務器 ;
  • 4.給主對話框類添加一個 WM_CLOSE 函數,在其中將 kernel 關閉;
  • 5.我們可以打開昨天寫的 Server ,將main中的部分代碼註釋掉,只留下:
int main()
{
	TCPKernel *pKernel = new TCPKernel;
	if(!pKernel->Open())
	{
		cout << "錯誤碼:"<<GetLastError();
		system("pause");
		return false;
	}
	// STRU_RESIGER_RQ srr;
	// srr.m_n_type = _DEF_PROTOCOL_LOGIN_RQ;
	// srr.m_id = 15046691259;
	// strcpy_s(srr.m_sz_name,45,"SLAM");
	// strcpy_s(srr.m_sz_password,45,"123456");
	// srr.m_sz_role = 0;

	// pKernel->RegisterRq(0,(char*)&srr);
	pKernel->LoginRq(0,(char*)&srr);
	system("pause");
	return true;
}
  • 5.運行 Server ,再運行 Author ,在 Server 的線程處理函數 ThreadRecv 中下一個斷點,在 Author 中的連接服務器處下一個端點,進行單步調試,測試是否有錯誤;

1.7 給主對話框添加控件

  • 1.添加三個 Static 控件、三個 Edit 控件、兩個 Button 控件;
  • 2.給 tel Edit 控件添加 value 型 LONG LONG 類型的變量,給 name Edit 控件和 passwoed Edit 控件添加 value 型 CString 類型的變量;
  • 3.完成註冊按鈕;
    • 1.首先獲取對話框上的數據,並創建一個 STRU_RESIGER_RQ 結構體對象,用來存放從對話框上取下來的數據;
    • 2.將取到的數據通過 Kernel 發送出去;
void CAuthorDlg::OnBnClickedButton1()
{
	UpdateData(TRUE);

	STRU_RESIGER_RQ srr;
	srr.m_n_type = _DEF_PROTOCOL_REGISTER_RQ;
	srr.m_sz_role = role_author;
	srr.m_id = m_edit_tel;
	strcpy_s(srr.m_sz_name, sizeof(srr.m_sz_name), m_eidt_name);
	strcpy_s(srr.m_sz_password, sizeof(srr.m_sz_password), m_eidt_passwd);

	theApp.m_p_kernel->SendData((char*)&srr, sizeof(srr));
}

1.8 給核心處理類中添加一個處理註冊回覆的函數 RegisterRs

  • 1.給這個函數添加消息映射表;
  • 2.在這個函數中首先獲取 STRU_RESISTER_RS 結構體指針對象;
  • 3.判斷指針對象中的結果屬性是否爲真;
bool TCPKernel::RegisterRs(char* szbuf)
{
	STRU_RESISTER_RS* p_srr = (STRU_RESISTER_RS*)szbuf;
	char* p_sz_result = "register_fail";
	if(p_srr->m_sz_result == register_success)
		p_sz_result = "register_success";
	AfxMessageBox(p_sz_result);

	return true;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章