栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

vs2019 C++学习

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

vs2019 C++学习

文章目录
  • 指针学习
    • 0参考资料
    • 1. 指针
    • 2. 二级指针:存放的内容是变量地址的地址
    • 3 const 修饰
    • 4函数指针
  • 内存管理
    • 0.参考资料
    • 1.C++中内存分为5个区
    • 2 堆与栈的区别
    • 3保守的使用内存分配,重载new/delete
    • 4.常见的内存错误及其策略
    • 5 数组与指针的对比
  • 回调函数
    • 0 学习资料
    • 1. 对Person的一组对象进行排序
    • 2. 实现回调的三种方式
  • 编程练习
    • 0
    • 1阶乘
    • 2. 拆分字符串
    • 3建立MFC对话框过程
    • 4 删除目录
    • 5 以''拆分一个缓冲
    • 6MFC按照界面规范重新布局下面的窗口
    • 7.编写一个表格控件类
    • 8 网络协议
  • 网络协议
    • 1TCP通信
  • socket通信/windows
    • 0
    • 1两种Internet套接字类型
    • 2.OSI网络模型,TCP/IP网络模型
    • 3确认信息的三要素:IP,MAC,Port
    • socket中的函数
    • socket 程序演示

指针学习 0参考资料

博客
C/C++指针详解之基础篇, 尘海折柳
C/C++指针详解之提高篇, 尘海折柳

1. 指针

(1)指针是特殊的变量,存放的内容是变量地址
(2)通过指针访问数组元素

#include
using namespace std;
int main() {
	int a[]={ 8,5,85,850,8500 };
	int* pa = a;
	//用数组名和指向数组名的指针打印数组元素
	for (int i = 0; i < sizeof(a)/sizeof(int); i++)   cout << a[i] << " ";
	cout << endl;
	for (int i = 0; i < sizeof(a) / sizeof(int); i++) cout << *(pa+i) << " "; 
	cout << endl;

	return 0;
}

(3)数组名可以看成是特殊的指针,能改变指向的内容不能改变指向,所以将数组名a+1是不对的
(4)指针数组:是数组,数组中每个元素是指针,char * a[85]等价于char* (a[85])

#include
using namespace std;
int main() {
	const char* wyb[] = { "wyb","is","ssj","zkad","bb" };
	for (int i = 0; i < sizeof(wyb) / sizeof(wyb[0]); i++) cout << wyb[i] << " "; 
	cout << endl;
	return 0;
}
2. 二级指针:存放的内容是变量地址的地址

(1)二级指针能改变一级指针的指向

#include
using namespace std;
int main() {
	int i = 85;
	int* pi = &i;
	int** ppi = π
	cout << "i=" << i << "t*pi=" << *pi << "tt**ppi=" << **ppi << endl;

	*pi = 850;
	int b = 8500;
	*ppi = &b; //修改ppi的内容使得:pi由指向a变为指向b
	cout << "i=" << i << "t*pi=" << *pi << "t**ppi=" << **ppi << endl;

	return 0;
}

(2)二级指针的步长:指针的步长是存储的内容的类型的大小,二级指针存储的内容是一级指针,一级指针的大小是4字节

#include
using namespace std;
int main() {
	double i = 85;
	double* pi = &i;
	double** ppi = π
	cout << "*pi的地址:" << pi << "pi走一步*(pi+1)的地址:" << pi + 1 << endl;
	cout << "pi的步长是:" <<(int) (pi + 1) -(int) pi << endl;//8

	cout << "*ppi的地址:" << ppi << "ppi走一步*(ppi+1)的地址:" << ppi + 1 << endl;
	cout << "ppi的步长是:" << (int)(ppi + 1) - (int)ppi << endl;//4
	return 0;
}

(3)用二级指针指向指针数组

#include
using namespace std;
int main() {
	const char* wyb[] = { "wyb","is","ssj","zkad","bb" };
	const char** ppwyb = wyb;
	//用指针数组名和指向数组名的二级指针打印
	for (int i = 0; i < sizeof(wyb) / sizeof(wyb[0]); i++) cout << wyb[i] << " "; 
	cout << endl;
	for (int i = 0; i < sizeof(wyb) / sizeof(wyb[0]); i++) cout << *(ppwyb+i) << " ";
	cout << endl;
	return 0;
}

通过在指针数组增加NULL,使得二级指针打印的时候不需要提前计算出维度

#include
using namespace std;
int main() {
	const char* wyb[] = { "wyb","is","ssj","zkad","bb",NULL };
	const char** ppwyb = wyb;
	//在指针数组末尾增加NULL,使得二级指针遍历时不需要提前计算指针数组元素个数
	while (*ppwyb != NULL) { cout << *ppwyb++ << " "; }
	cout << endl;
	return 0;
}

(4)在堆上申请一维数组

#include
using namespace std;

//用一维指针申请内存
char* allocSpace(int n) {
	char* p =(char*) malloc(n*sizeof(char));
	//char* p = new char[n * sizeof(char)];//C++中的,但是听说malloc/free更快,我还小白
	return p;
}
//用二维指针申请内存,返回-1申请失败
int allocSpace_1(char **p, int n) {
	*p = (char*)malloc(n * sizeof(char));
	/)
	: CDialogEx(IDD_EXERCISE31_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINframe);
	m_pTipDlg = NULL;
}

修改onBnClickedAddButton()的函数体

void Cexercise31Dlg::OnBnClickedCancel()
{
	// TODO: 在此添加控件通知处理程序代码
	if (NULL == m_pTipDlg1){
		// 创建非模态对话框实例   
		m_pTipDlg1 = new CTipDlg1();
		m_pTipDlg1->Create(IDD_TIP_DIALOG, this);
	}
	// 显示非模态对话框   
	m_pTipDlg1->ShowWindow(SW_SHOW);
	//CDialogEx::onCancel();
}

//CDialogEx::onCancel();不注释会发生闪退,注释了以后点击主窗口的叉号键不能正常退出

5该对话框背景为一位图拉伸铺满整个窗口显示
不知道怎么弄,先手拉吧->_->

6.点击窗口关闭按钮退出程序
重写onclose()
右击CxxxDlg类,点击属性,点击重写

void Cexercise31Dlg::OnClose()
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	EndDialog(IDCANCEL);    //关闭窗口  
	CDialog::OnClose();

}

7.按回车、ESC键不执行任何操作
重写CXXXDlg类中的Cexercise31Dlg::PreTranslateMessage(MSG* pMsg)
可以是ESC键失效

BOOL Cexercise31Dlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) return TRUE;  //去掉esc退出功能	
	//if(pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_RETURN) return TRUE; //去掉回车退出功能,当然在这里也会导致整个窗体的失去回车效果	
	else  //其他正常
		return CDialogEx::PreTranslateMessage(pMsg);
}

这段重写可以使enter和esc都失效

BOOL Cexercise31Dlg::PreTranslateMessage(MSG* pMsg){
	if (pMsg->message == WM_KEYDOWN)//会使所有按钮失效
	{
		switch (pMsg->wParam)
		{
		case VK_RETURN:
			return TRUE;
		case VK_ESCAPE:
			return TRUE;
		}
	}
	return CDialog::PreTranslateMessage(pMsg);
}
4 删除目录

这个对我来说太困难了 ||_||
我得分步骤慢慢来
WIN32_FIND_DATA结构体,第一个一属性DWORD dwFileAttributes; //文件属性

	typedef struct _WIN32_FIND_DATA {
		DWORD dwFileAttributes; //文件属性
		FILETIME ftCreationTime; // 文件创建时间
		FILETIME ftLastAccessTime; // 文件最后一次访问时间
		FILETIME ftLastWriteTime; // 文件最后一次修改时间
		DWORD nFileSizeHigh; // 文件长度高32位
		DWORD nFileSizeLow; // 文件长度低32位
		DWORD dwReserved0; // 系统保留
		DWORD dwReserved1; // 系统保留
		TCHAR cFileName[MAX_PATH]; // 长文件名
		TCHAR cAlternateFileName[14]; // 8.3格式文件名
	} WIN32_FIND_DATA, * PWIN32_FIND_DATA;

FindFirstFile函数原型

HANDLE FindFirstFileW(
		LPCWSTR            lpFileName,
		LPWIN32_FIND_DATAW lpFindFileData
	);

lpFileName是目录或路径以及文件名。文件名可以包含通配符(*)(?),lpFileName不能为NULL,无效字符串(缺少),以()结尾
lpFindFile是指针,用来接收收到的文件或目录信息

可以递归的查看路径wstrDir下名字带有字符串s文件和文件夹
递归的意思是指如果某个子文件夹下含有带有字符串s文件和文件夹也会被删除

#include
#include
#include
using namespace std;
//查看指定目录中所有直接文件和目录
void ListFilesInDirectory(wstring wstrDir, wstring s) {
	if (wstrDir.empty()) return;
	HANDLE hFind;
	//WIN32_FIND_DATA结构体,第一属性DWORD dwFileAttributes; //文件属性
	WIN32_FIND_DATA findData;
  //在目录后添加“*”,目录中的所有直接文件和目录
	wstring wstrTempDir = wstrDir + (L"\*");
	hFind = FindFirstFile(wstrTempDir.c_str(), &findData);
	if (hFind == INVALID_HANDLE_VALUE) return;
	do {
		//过滤掉(.)
		if (wcscmp(findData.cFileName, L".") == 0) continue;
		//如果字符串中没有某个子串就过滤掉,If the string is not found, wcswcs() returns NULL.
		if (wcswcs(findData.cFileName, s.c_str()) == NULL) continue;
		wstring wstrFilename;
		wstrFilename.assign(wstrDir);
		wstrFilename.append(L"\");
		wstrFilename.append(findData.cFileName);
		wcout << wstrFilename << endl;//(.)和(..)分别指当前目录和上级目录
		if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
			//如果是目录就递归的删除
			ListFilesInDirectory(wstrFilename, s.c_str());
		}
	} while (FindNextFile(hFind, &findData) != 0);
	FindClose(hFind);
}
int main() {
	ListFilesInDirectory(L"F:\C++\test\testFile1\test1",L"1");
	return 0;
}
#include
#include
#include
using namespace std;
void RemoveAllFiles1(wstring wstrDir) {
	if (wstrDir.empty()) return;
	HANDLE hFind;
	WIN32_FIND_DATA findData;
	wstring wstrTempDir = wstrDir + (L"\*");
	hFind = FindFirstFile(wstrTempDir.c_str(), &findData);
	if (hFind == INVALID_HANDLE_VALUE) return;
	do {
		wstring wstrFilename;
		wstrFilename.assign(wstrDir);
		wstrFilename.append(L"\");
		wstrFilename.append(findData.cFileName);
		if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
			RemoveAllFiles1(wstrFilename);
		}
		else {
			DeleteFile(wstrFilename.c_str());
		}
	} while (FindNextFile(hFind, &findData) != 0);
	FindClose(hFind);
	RemoveDirectory(wstrDir.c_str());
}
//查看指定目录中所有直接文件和目录
BOOL RemoveAllFiles( wstring wstrDir, wstring s ){
	if (wstrDir.empty()) return false;
	HANDLE hFind;
	//WIN32_FIND_DATA结构体,第一属性DWORD dwFileAttributes; //文件属性
	WIN32_FIND_DATA findData;
	//在目录后添加“*”,目录中的所有直接文件和目录
	wstring wstrTempDir = wstrDir + (L"\*");
	hFind = FindFirstFile(wstrTempDir.c_str(), &findData);
	if (hFind == INVALID_HANDLE_VALUE) return false;
	do {
		wstring wstrFilename;
		wstrFilename.assign(wstrDir);
		wstrFilename.append(L"\");
		wstrFilename.append(findData.cFileName);
		//如果字符串中没有某个子串就过滤掉,
		if (findData.cFileName!=NULL&& wcswcs(findData.cFileName, s.c_str()) != NULL) {
			RemoveAllFiles1(wstrFilename);
		}
	} while (FindNextFile(hFind, &findData) != 0);
	FindClose(hFind);
	//RemoveDirectory(wstrDir.c_str());
	return TRUE;
}

it did hhh ^ O ^ runrunrun~

还差:a.改格式

BOOL RemoveSpecifiedDir(LPCTSTR lpszDirPath, LPCTSTR lpszSpecifiedDir)

**c.“exe放到任意一个目录中,执行exe后就能把该目录下所有指定目录删除”**是要自动获取.exe所在文件夹路径?

string GetExePath()
{
	char szFilePath[MAX_PATH + 1] = { 0 };
	GetModuleFileNameA(NULL, szFilePath, MAX_PATH);
	
	(strrchr(szFilePath, '\'))[0] = 0; // 删除文件名,只获得路径字串//
	string path = szFilePath;
	return path;
}
5 以''拆分一个缓冲

怎么把带的字符串输入到LPCTSTR里啊 搞不明白
这个代码输不进去,maybe 看文件的输入方式可以
一个方法就是赋值的时候不要经过string或者CString,直接
LPCTSTR lpszSrc = (LPCTSTR)(_T("wybwybwyb"));
但这要要从test()函数里自己输入

#include
#include
#include
#include
#include  

typedef std::vector CStringArray;
void SplitBufferByZero(LPCTSTR lpBuf, int nBufLen, CStringArray& szaDst);

void test() {//只能人工验证了吧。。。
	//CString str(_T("wybwybwyb"));
	//LPCTSTR lpszSrc = (LPCTSTR)str;
	LPCTSTR lpszSrc = (LPCTSTR)(_T("wybwybwyb"));//将string 转换为LPCTSTR
	CStringArray szaDst;
	SplitBufferByZero(lpszSrc,20, szaDst);
	for (int i = 0; i < szaDst.size(); i++) {
		//std::cout << (LPCTSTR)szaDst[i]<< " ";
		printf("%ls", (LPCTSTR)szaDst[i]);
	}
	std::cout << std::endl;
}

void SplitBufferByZero(LPCTSTR lpBuf, int nBufLen, CStringArray& szaDst) {
	CString tmp;
	//std::string s;
	for (int i = 0; i < nBufLen; i++) {
		tmp += lpBuf[i];
		if (lpBuf[i] == '') {//把临时串写进 szaDst
			szaDst.push_back(tmp);//分割以指定字符串结尾
			tmp = _T("");
		}
		
	}
	if (tmp != _T("")) szaDst.push_back(tmp);
}

int main1() {
	test();
	return 0;
}


6MFC按照界面规范重新布局下面的窗口

1.建议参考IE、Outlook、QQ、MSN等软件的选项设置界面

1.添加4 个static text:服务名称,可执行文件的路径,启动类型,服务状态
2. 2个下拉框 :添加2个Combo Box控件,ID分别为设置为IDC_NAME_COMBO,IDC_TYPE_COMBO,Type属性设为Drop List,,编辑框不允许用户输入,Sort属性设为False,以取消排序显示。
再添加一个静态文本控件和一个编辑框,静态文本控件的Caption属性设为“您选择的网站:”,编辑框的ID设为IDC_SEL_WEB_EDIT,Read Only属性设为True。此时的对话框模板如下图:

3 添加5个Button:浏览IDC_LOOK_BUTTON,启动IDC_START_BUTTON,停止IDC_STOP_BUTTON,注册IDC_REGISTER_BUTTON,注销IDC_LOGOUT_BUTTON
4. 去掉“确定按钮”,把“取消”按钮改成“退出”
5. 加一个与浏览关联的编辑框IDC_LOOK_EDIT,显示打开文件对话框中选择的文件路径
6.为浏览按钮IDC_LOOK_BUTTON添加事件处理程序,点击消息的消息处理函数
Cexercise5Dlg::onBnClickedLookButton()

void Cexercise5Dlg::OnBnClickedLookButton()
{
	// TODO: 在此添加控件通知处理程序代码
	TCHAR szFilter[] = _T("文本文件(*.txt)|*.txt|所有文件(*.*)|*.*||");
	// 构造打开文件对话框   
	CFileDialog fileDlg(TRUE, _T("txt"), NULL, 0, szFilter, this);
	CString strFilePath;
	// 显示打开文件对话框   
	if (IDOK == fileDlg.DoModal())
	{
		// 如果点击了文件对话框上的“打开”按钮,则将选择的文件路径显示到编辑框里   
		strFilePath = fileDlg.GetPathName();
		SetDlgItemText(IDC_LOOK_EDIT, strFilePath);
	}
}

保存文件类似的有代码

void CExample17Dlg::OnBnClickedSaveButton()   
{   
    // TODO: Add your control notification handler code here   
    // 设置过滤器   
    TCHAR szFilter[] = _T("文本文件(*.txt)|*.txt|Word文件(*.doc)|*.doc|所有文件(*.*)|*.*||");   
    // 构造保存文件对话框   
    CFileDialog fileDlg(FALSE, _T("doc"), _T("my"), OFN_HIDEREADonLY | OFN_OVERWRITEprompt, szFilter, this);   
    CString strFilePath;   
   
    // 显示保存文件对话框   
    if (IDOK == fileDlg.DoModal())   
    {   
        // 如果点击了文件对话框上的“保存”按钮,则将选择的文件路径显示到编辑框里   
        strFilePath = fileDlg.GetPathName();   
        SetDlgItemText(IDC_SAVE_EDIT, strFilePath);   
    }   
}
  1. 给启动下拉列表添加选项
    为组合框IDC_TYPE_COMBO添加控件变量(属性里添加) CComboBox m_comboType;
    修改对话框初始函数BOOL Cexercise5Dlg::onInitDialog()
// TODO: Add extra initialization here   
    // 为组合框控件的列表框添加列表项   
    m_comboWeb.AddString(_T("手动"));    
    m_comboWeb.AddString(_T("自动"));   
    // 默认选择第一项   
    m_comboWeb.SetCurSel(0);   
    SetDlgItemText(IDC_SEL_WEB_EDIT, _T("手动"));   

做出来的界面就是这样的~
不懂服务名称是什么意思,以及服务状态为什么是灰色的,要触发什么还是

7.编写一个表格控件类 8 网络协议

下面的这段代码可以粗糙的客户端向服务器发送一个协议结构体,然后服务器输出这个结构体的信息
客户端

#include
#include
#include
#pragma comment(lib, "ws2_32.lib")
#include
#include
struct TUserInfo {
	char name[31];
	char mima[31];
	char address[63];
	short port;
};
struct messageHeader {
	char cmd;
	int lenData;
};
const int cmdLen = 1, dataLen = 4;
const int nameLen = 31, miamaLen = 31, addressLen = 63, portLen = 2;

using namespace std;

void sendMessage() {
	TUserInfo wyb = { "wyb","software","127.0.0.1",4477 };
	//初始化ddl
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	//创建套接字
	SOCKET clntSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	//向服务端发起请求
	struct sockaddr_in sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));
	sockAddr.sin_family = PF_INET;
	sockAddr.sin_addr.S_un.S_addr = inet_addr(wyb.address);
	sockAddr.sin_port = htons(wyb.port);
	connect(clntSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
	//客户端发送数据
	while (1) {
		char str[150] = { '' };
		for (int i = 0; i < cmdLen; i++) str[i] = '1';
		for (int i = cmdLen + dataLen; i < cmdLen + dataLen + nameLen; i++)
			str[i] = wyb.name[i-(cmdLen + dataLen)];
	   for (int i = cmdLen + dataLen + nameLen; i < cmdLen + dataLen + nameLen + miamaLen; i++)
			str[i] = wyb.mima[i-(cmdLen + dataLen + nameLen)];
	  for (int i = cmdLen + dataLen + nameLen + miamaLen; i < cmdLen + dataLen + nameLen + miamaLen+ addressLen; i++)
		    str[i] = wyb.address[i-(cmdLen + dataLen + nameLen + miamaLen)];
	  string tmp= to_string(wyb.port);
	  for (int i = cmdLen + dataLen + nameLen + miamaLen + addressLen; i < cmdLen + dataLen + nameLen + miamaLen + addressLen + tmp.size(); i++)
		  str[i] = tmp[i-(cmdLen + dataLen + nameLen + miamaLen + addressLen)];
	  send(clntSock, str, 150, NULL);
		Sleep(10000);
	}
	//关闭套接字
	closesocket(clntSock);
	//终止使用ddl
	WSACleanup();
	//system("pause");

}
int main() {
	thread mythread(sendMessage);
	mythread.join();
	std::cout << "主线程执行" << std::endl;
	system("pause");
	return 0;
}

服务器

#include
#include
#include
#pragma comment(lib, "ws2_32.lib")
#include

struct TUserInfo {
	char name[31];
	char mima[31];
	char address[63];
	short port;
};
struct messageHeader {
	char mingling;
	int lenData;
};
using namespace std;

void sendMessage() {
	//初始化dll
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	//创建套接字
	SOCKET servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	//绑定套接字
	struct sockaddr_in sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));//每个字节都用0填充
	sockAddr.sin_family = PF_INET;
	sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	//InetPton(AF_INET, (LPCTSTR)"127.0.0.1", &sockAddr.sin_addr.S_un.S_addr);
	sockAddr.sin_port = htons(4477);
	bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
	//进入监听状态
	listen(servSock, 20);
	//接收客户端请求
	SOCKADDR clintAddr;
	int nSize = sizeof(SOCKADDR);
	SOCKET clntSock = accept(servSock, (SOCKADDR*)&sockAddr, &nSize);
	//向客户端发送数据
	//接收服务器传回的数据
	char szBuffer[MAXBYTE] = { 0 };
	recv(clntSock, szBuffer, MAXBYTE, NULL);
	//输出接收到的数据
	for (int i = 0; i < MAXBYTE; i++) {
		if (szBuffer[i] != '') cout << szBuffer[i];
	}
	//关闭套接字
	closesocket(servSock);
	closesocket(clntSock);
	//终止dll的使用
	WSACleanup();

}
int main() {
	thread mythread(sendMessage);
	mythread.join();
	std::cout << "主线程执行" << std::endl;
	system("pause");
	return 0;
}

本题需要实现如下功能:
1.1某网络协议要求结构体成员四字节对齐和使用小印第安模式,依照此规则定义一个结构体TUserInfo,包含以下成员:用户名(31字节字符串)、密码(31字节字符串)、地址(63字节字符串)、端口(2字节短整型)。
1.2消息头结构体定义:命令字(1字节)、数据长度(4字节整型)。
1.3客户端程序开一个线程,定义一个TUserInfo的对象usrInfo并初始化,地址为服务器机器IP,端口为4477,用户名为自己的名字,密码为Software;然后将usrInfo加消息头(命令字为0x01)每隔10s发送给usrInfo中的地址和端口。
1.4服务器程序开一个线程,接受客户端向4477端口发来的消息,对0x01消息分析其数据(TUserInfo),打印出每次收到的用户名、密码、地址和端口等信息。在时间充裕的情况下可以考虑多客户端同时连接的情况。
要怎么处理头部1个字节的整数转化成字符串需要3个字节
服务器端:

#include
#include
#include
#pragma comment(lib, "ws2_32.lib")
#include

struct TUserInfo {
	char name[31];
	char mima[31];
	char address[63];
	short port;
};
struct messageHeader {
	char mingling;
	int lenData;
};
const int cmdLen = 1, dataLen = 4;
const int nameLen = 31, miamaLen = 31, addressLen = 63, portLen = 2;
using namespace std;

void sendMessage() {
	//初始化dll
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	//创建套接字
	SOCKET servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	//绑定套接字
	struct sockaddr_in sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));//每个字节都用0填充
	sockAddr.sin_family = PF_INET;
	sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	//InetPton(AF_INET, (LPCTSTR)"127.0.0.1", &sockAddr.sin_addr.S_un.S_addr);
	sockAddr.sin_port = htons(4477);
	bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
	//进入监听状态
	listen(servSock, 20);
	SOCKADDR clintAddr;
	int nSize = sizeof(SOCKADDR);
	char szBuffer[MAXBYTE] = { 0 };

	while (1) {
		SOCKET clntSock = accept(servSock, (SOCKADDR*)&sockAddr, &nSize);
		//接收客户端发送来的数据
		int strLen=recv(clntSock, szBuffer, MAXBYTE, NULL);
		//如果命令字是1,就打印打印出每次收到的用户名、密码、地址和端口等信息
		int cmd = szBuffer[0]-'0';
		if (cmd == 1) {
			cout << "name: ";
			for (int i = cmdLen + dataLen; i < cmdLen + dataLen + nameLen; i++) {
				if (szBuffer[i] == '') continue;
				cout << szBuffer[i];
			}
			cout << "    mima:";
			for (int i = cmdLen + dataLen + nameLen; i < cmdLen + dataLen + nameLen + miamaLen; i++) {
				if (szBuffer[i] == '') continue;
				cout << szBuffer[i];
			}
			cout << "    address:";
			for (int i = cmdLen + dataLen + nameLen + miamaLen; i < cmdLen + dataLen + nameLen + miamaLen + addressLen; i++) {
				if (szBuffer[i] == '') continue;
				cout << szBuffer[i];
			}
			cout << "    port:";
			for (int i = cmdLen + dataLen + nameLen + miamaLen + addressLen; i < 150; i++) {
				if (szBuffer[i] == '') continue;
				cout << szBuffer[i];
			}
			cout << endl;
		}
		
		//关闭套接字
		closesocket(clntSock);
		memset(szBuffer, 0, MAXBYTE);
	}
	closesocket(servSock);
	//终止dll的使用
	WSACleanup();

}
int main() {
	thread mythread(sendMessage);
	mythread.join();
	std::cout << "主线程执行" << std::endl;
	system("pause");
	return 0;
}

客户端:

#include
#include
#include
#pragma comment(lib, "ws2_32.lib")
#include
#include
struct TUserInfo {
	char name[31];
	char mima[31];
	char address[63];
	short port;
};
struct messageHeader {
	char cmd;
	int lenData;
};
const int cmdLen = 1, dataLen = 4;
const int nameLen = 31, miamaLen = 31, addressLen = 63, portLen = 2;

using namespace std;

void sendMessage() {
	TUserInfo wyb = { "wyb","software","127.0.0.1",4477 };
	//初始化ddl
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	
	//向服务端发起请求
	struct sockaddr_in sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));
	sockAddr.sin_family = PF_INET;
	sockAddr.sin_addr.S_un.S_addr = inet_addr(wyb.address);
	sockAddr.sin_port = htons(wyb.port);
	
	//客户端发送数据
	char str[150] = { '' };
	for (int i = 0; i < cmdLen; i++) str[i] = '1';
	for (int i = cmdLen + dataLen; i < cmdLen + dataLen + nameLen; i++)
		str[i] = wyb.name[i - (cmdLen + dataLen)];
	for (int i = cmdLen + dataLen + nameLen; i < cmdLen + dataLen + nameLen + miamaLen; i++)
		str[i] = wyb.mima[i - (cmdLen + dataLen + nameLen)];
	for (int i = cmdLen + dataLen + nameLen + miamaLen; i < cmdLen + dataLen + nameLen + miamaLen + addressLen; i++)
		str[i] = wyb.address[i - (cmdLen + dataLen + nameLen + miamaLen)];
	string tmp = to_string(wyb.port);
	for (int i = cmdLen + dataLen + nameLen + miamaLen + addressLen; i < cmdLen + dataLen + nameLen + miamaLen + addressLen + tmp.size(); i++)
		str[i] = tmp[i - (cmdLen + dataLen + nameLen + miamaLen + addressLen)];
	
	while (1) {
		//创建套接字
		SOCKET clntSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
		connect(clntSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
		send(clntSock, str, 150, NULL);
		Sleep(10000);
		closesocket(clntSock);
	}
	
	//终止使用ddl
	WSACleanup();
	//system("pause");

}
int main() {
	thread mythread(sendMessage);
	mythread.join();
	std::cout << "主线程执行" << std::endl;
	system("pause");
	return 0;
}

网络协议 1TCP通信

TCP是面向连接、可靠传输、面向字节流的传输层协议
服务端操作流程
(1)创建套接字接口:在内核中创建socket结构体,关联进程与网卡联系
(2)为套接字绑定地址信息:五元组{源IP,目标IP,源端口,目标端口,协议},必须主动绑定
(3)监听:只有处于监听状态的套接字才会接受客户端的连接请求,服务端为每个客户端请求创建一个新的socket结构体,通过这个结构体与客户端通信
(4)获取socket的句柄
(5)收发数据
(6)关闭套接字

客户端流程:
(1)创建套接字
(2)为套接字绑定地址信息,不推荐主动绑定地址,降低端口冲突的概率
(3)向服务端发起连接请求
(4)收发数据
(5)关闭套接字

socket通信/windows 0

socket 是计算机之间通信的一种约定或方式
windows区分socket和文件,Windows把socket当作一个网络连接对待

1两种Internet套接字类型

(1)流格式套接字 SOCK_STREAM:
a. 可靠的、双向的通信数据流:使用了TCP协议(The Transmission Control Protacol)
b. 顺序传输,
c. 数据的发送和接收不同步:流格式套接字内部有一个缓冲区,socket传输的数据保存到这个缓冲区,接收的数据有可能在缓冲区满后一次读取,也可能分好几次读取
应用:HTTP, FTP
(2)数据宝格式套接字SOCK_DGRAM
计算机只管传输数据,不作数据校验,传输效率高
a. 强调快速,非顺序,数据可能丢失或销毁,使用UDP协议(User Datagram Protocol)
b. 限制每次传输数据大小
c.数据的发送和接收是同步的
应用:DNS,即时聊天工具

2.OSI网络模型,TCP/IP网络模型

OSI模型把网络通信工作分为七层:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层
TCP/IP 模型四层:网络接口层,网际层,传输层,应用层

socket编程是在传输层基础上
计算机通信时需要遵循原则:
同一层通信,每层功能相同,数据逐层传输,每一层可以使用下层提供的服务并且向上层提供服务

3确认信息的三要素:IP,MAC,Port

(1)IP地址(Internet Protocol Address):通常一个局域网拥有一个IP地址
(2)MAC地址(Media Access Control Address):也称局域网地址,以太网地址,物理地址,唯一标识一台计算机
(3)端口号(Port Number):计算机为每个网络程序分配一个独一无二的端口号

socket中的函数

(1)socket()函数创建套接字:

SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
socket 程序演示

下面的程序客户端可以接收来自服务端发送的消息,
要先打开server.exe,再打开client.exe,否则收不到;要打开工程属性->C/C++常规->关闭sdl检查,否则代码sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
会发生警告 C4996 ‘inet_addr’: Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings client82

server.cpp

#include
#include
//#include 
#pragma comment(lib, "ws2_32.lib")

int main() {
	//初始化dll
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	//创建套接字
	SOCKET servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	//绑定套接字
	struct sockaddr_in sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));//每个字节都用0填充
	sockAddr.sin_family = PF_INET;
	sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	//InetPton(AF_INET, (LPCTSTR)"127.0.0.1", &sockAddr.sin_addr.S_un.S_addr);
	sockAddr.sin_port = htons(2850);
	bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
	//进入监听状态
	listen(servSock, 20);
	//接收客户端请求
	SOCKADDR clintAddr;
	int nSize = sizeof(SOCKADDR);
	SOCKET clntSock = accept(servSock, (SOCKADDR*)&sockAddr, &nSize);
	//向客户端发送数据
	const char* str = "hello wyb!n";
	send(clntSock, str, strlen(str) + 1, NULL);
	//关闭套接字
	closesocket(servSock);
	closesocket(clntSock);
	//终止dll的使用
	WSACleanup();


	return 0;
}

client.cpp

#include
#include
#pragma comment(lib, "ws2_32.lib")

int main() {
	//初始化ddl
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	//创建套接字
	SOCKET clntSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	//向服务端发起请求
	struct sockaddr_in sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));
	sockAddr.sin_family = PF_INET;
	sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	sockAddr.sin_port = htons(2850);
	connect(clntSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
	//接收服务器传回的数据
	char szBuffer[MAXBYTE] = { 0 };
	recv(clntSock, szBuffer, MAXBYTE, NULL);
	//输出接收到的数据
	printf("message from server: %sn", szBuffer);
	//关闭套接字
	closesocket(clntSock);
	//终止使用ddl
	WSACleanup();
	system("pause");

	return 0;

}

一博实在太帅了,又福气旺旺

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/456764.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号