RemoteCtrl.cpp
// RemoteCtrl.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。
//#include "pch.h"
#include "framework.h"
#include "RemoteCtrl.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif// 唯一的應用程序對象CWinApp theApp;using namespace std; int main()
{int nRetCode = 0;HMODULE hModule = ::GetModuleHandle(nullptr);if (hModule != nullptr){// 初始化 MFC 并在失敗時顯示錯誤if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0)){// TODO: 在此處為應用程序的行為編寫代碼。wprintf(L"錯誤: MFC 初始化失敗\n");nRetCode = 1;}else{// TODO: socket//套接字初始化WSADATA data;WSAStartup(MAKEWORD(1, 1), &data); //TODO:返回值處理SOCKET serv_sock = socket(PF_INET, SOCK_STREAM, 0); //使用TCP//TODO:校驗,不一定創建成功了sockaddr_in serv_adr;memset(&serv_adr, 0, sizeof(serv_adr)); //給清0一下serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = INADDR_ANY;serv_adr.sin_port = htons(9527);//綁定bind(serv_sock, (sockaddr*)&serv_adr, sizeof(serv_adr)); //TODO//TODO:listen(serv_sock, 1); //控制端是1對1的char buffer[1024];recv(serv_sock, buffer, sizeof(buffer), 0);send(serv_sock, buffer, sizeof(buffer), 0);closesocket(serv_sock);WSACleanup();}}else{// TODO: 更改錯誤代碼以符合需要wprintf(L"錯誤: GetModuleHandle 失敗\n");nRetCode = 1;}return nRetCode;
}
接下來我們想著去優化代碼
WSAStartup()
和WSACleanup()
函數是固定的,一個在程序初始化時候執行,一個在程序銷毀時候執行,那么有沒有一種東西,可以完成這種操作,有的,靜態變量。
靜態變量是在首次被調用時候初始化,在程序銷毀時候銷毀,全局的靜態函數會在main函數之前初始化,在main函數返回之后銷毀。
在main函數之前執行,是多線程環境還是單線程環境?
單線程環境,單線程不存在上鎖解鎖互斥之類的
套路化代碼
但是我們這是一個MFC工程,我們需要考慮不是所有操作都需要到main函數里面實現,有些操作可以在main函數之前完成,有些可以在main函數返回以后完成,靜態全局變量滿足這個需求,我們需要添加一個自己的類
編輯器細節1
添加類和添加類向導的區別,一個是添加自己的類,一個是添加MFC的類
添加上CServerSocket全局靜態類(獨立于main之外),在構造函數里面添加上套接字的初始化函數,在析構函數里面添加上套接字的清理函數
#pragma once
#include "pch.h"
#include "framework.h"class CServerSocket
{
public:CServerSocket(){if (InitSockEnv() == FALSE) {MessageBox(NULL, _T("無法初始化套接字環境,請檢查網絡設置!"), _T("初始化錯誤!"), MB_OK | MB_ICONERROR);exit(0);}}~CServerSocket() {WSACleanup();}BOOL InitSockEnv() {WSADATA data;if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { //TODO:返回值處理}return FALSE;}return TRUE;}
};extern CServerSocket server;
為什么添加pch.h
和framework.h
頭文件?因為有些網絡編程的頭文件在這框架的頭文件里面
那么我們怎么在RemoteCtrl.cpp文件里面用上這個全局靜態類呢?
因為**聲明可以多次,定義只能一次。**所以我們在ServerSocket.cpp里面定義一個ServerSocket類的對象
然后在頭文件里面靠extern這個對象,來讓外面包含這個頭文件時候使用(被多次包含也沒有關系,因為可以多次聲明)
extern int i; //聲明,不是定義
int i; //聲明,也是定義
然后我們需要明確一點的是進main之前,我們肯定是單線程,開天辟地前的井井有條,到main,我們可能開始需要定義多線程,然后退出main時也只剩下一個進程了,毀天滅地后的井井有條
代碼如下:
int main()
{int nRetCode = 0;//int a;HMODULE hModule = ::GetModuleHandle(nullptr);if (hModule != nullptr){// 初始化 MFC 并在失敗時顯示錯誤if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0)){// TODO: 在此處為應用程序的行為編寫代碼。wprintf(L"錯誤: MFC 初始化失敗\n");nRetCode = 1;}else{ // TODO: 在此處為應用程序的行為編寫代碼。server;WSADATA data;SOCKET serv_sock = socket(PF_INET, SOCK_STREAM, 0); //TCP//TODO:校驗sockaddr_in serv_adr, client_adr;memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = INADDR_ANY; //服務器可能有4個IP等,監聽所有地址,被控機子不只有yserv_adr.sin_port = htons(9527);//綁定bind(serv_sock, (sockaddr*)&serv_adr, sizeof(serv_adr)); //TODO//TODO:listen(serv_sock, 1); //控制端是1對1的char buffer[1024];//int cli_sz = sizeof(client_adr);//SOCKET client = accept(serv_sock, (sockaddr*)&client_adr,&cli_sz)//recv(serv_sock, buffer, sizeof(buffer), 0);//send(serv_sock, buffer, sizeof(buffer), 0);closesocket(serv_sock);//全局的靜態變量}}
當下還沒有解決的問題:
要是別人繼續定義一個CServerSocket的局部對象,進去后又執行一道構造函數,退出時候提前執行了析構函數,那么網絡環境全部亂套了
下一篇文章就是要用單例模式來解決這個問題