C++高并发网络通信引擎学习记录。

版权声明:This is the author's original work. Please indicate the source for reprinting. https://blog.csdn.net/u011499443/article/details/84259044

2018.11.19 周一
学了 C/C++ 语言这么久了,从来没有真正的做过一个完整的项目,总觉得缺了点什么,所以决定找一个项目来认认真真跟着做。最后在朋友的推荐下选择了刘向东的《C++百万并发网络通信引擎架构与实现》,学习这个项目我大概给自己规划了3个学习阶段:

  1. 跟着老师的教学动手敲代码,从头到尾把项目敲一遍;
  2. 根据自己在学习过程中做的笔记,不看教学视频从零实现一遍,中途有不会的地方可以对照以前的代码;
  3. 自己不看前两次的代码,再次从零实现一遍;
    相信如果自己能按照计划做一遍的话,那么对于 C/C++语言、系统编程、网络编程、网络通信、项目工程的构建过程,会有自己的一套很深刻的理解。对自己的帮助那将是极大的。

---------------------------------------------还算华丽的分割线---------------------------------------

说干就干,今天学习了两集使用 VS2017 构建项目的基础课程,学到了一个很有用的东西:
工程目录配置:通过右击项目->属性,然后更改输出目录和中间目录的目录配置,可以使得我们一个项目的输出文件和源文件完完全全的分隔开来(存放在不同的文件夹中),保证了编译输出不会“污染”源文件目录。
这里放目录配置的环境变量:
输出目录:$(SolutionDir)../bin/$(Platform)/$(Configuration)/
中间目录:$(SolutionDir)../temp/$(Platform)/$(Configuration)/$(ProjectName)/

2018.11.20 周二
今天学习了基本的程序调试方法和使用版本控制工具管理自己源文件。接下来就对今天的学习稍稍做个总结,记录一些自己认为有用的知识。
基本的程序调试方法可以总结为以下4个:

  1. 通过打印数据调试----这是平时很常用的程序调试方法,不过在使用的时候还有一个很有用的技巧,那就是把调试代码放在宏定义中,这样来,只有在 Debug 模式下调试代码才会参与编译,而在 Release 模式下调试代码就不会参与编译。
    #ifdef _DEBUG 调试代码... #end if // _DEBUG
  2. 使用断点进行程序调试----而又可以在断点上附加一些限制条件,比如 if i == 5;然后再进行一些输出或者其他的自己想要的操作,此时又可以叫做条件断点
  3. 单步调试----单步调试可以分为两个操作,1. 是逐过程;2.是逐语句;它们的区别简单的说就是逐过程不会进入函数,逐语句会进入函数。
  4. 添加监视----对于想要查看的变量,可以手动将它们添加到监视窗口中。快速监视有一个很特殊的作用,那就是查看一个指针指向的空间中每一个元素的值----因为在监视窗口中只会显示指针指向的空间的第一个元素的值。

接下来是学习使用版本控制工具来帮助管理自己的源代码文件。老师介绍的是使用 SVN 搭建一个源代码托管服务器,然后使用 SVN 客户端从服务器中拉取代码,操作挺简单的。
因为个人喜好原因,我选择了使用 GitHub 作为源码托管平台,然后工具是选择了 GitSourceTree。以后如果需要的话,我会考虑用 Git 搭建一个自己的代码托管平台。

2018.11.21 周三
今天是我学习这么久以来最高兴的一天,因为在今天我拿到了 tieto 的 offer。从去别的参加校招 10.29 号开始,到今天成功的拿到 offer,一共经历了24天,四轮面试,辛苦啊!拿到了 offer 不代表我可以松懈了,相反,我应该更加努力地学习了,加油!!!
因为时间原因,没能进行今天的通信引擎的学习,明天的学习目标是搞清楚怎么在 GitHub 上搭建自己的一个代码库,然后使用 SourceTree 提交代码。

2018.11.22 周四
今天一天都在外边奔波,把三方协议送到公司,然后又赶回学校问辅导员关于选择校外实习要注意哪些问题。
不得不说公司那边的环境是真的不错,今天正好出太阳了,就在周围走了走,感觉好棒啊。还看到了企鹅的分公司,还有阿里巴巴。明天估计还是要忙活半天,要下午两点才能去图书馆,不过几点去不是问题,重点是要去、然后好好学习。
加油!!!

2018.11.23 周五
今天把使用 SourceTree 连接 GitHub 代码库的问题解决了,总结一下使用 ssh 连接代码库步骤:

  1. 在 GitBash 界面创建一对 ssh 秘钥,其中 id_rsa 是私钥,id_rsa.pub 是公钥;
  2. 在 GitHub 账户的 setting 界面中添加 id_rsa.pub(公钥),以允许使用相应私钥的用户可以访问库;
  3. 在 SourceTree 选项界面的 SSH 客户端中添加 id_rsa(私钥),并选择 OpenSSH 方式;
  4. 之后就可以拉取 / 推送代码了;
  5. GitHub 的帮助文档

2018.11.24 周六
今天学习了如何使用虚拟机安装不同的操作系统环境,我选择的是 VMware。在安装完 VMware 之后,还需要一个工具来使得 VMware 可以安装 MacOS 操作系统,叫做 unlocker。下载地址在 GitHub 上。下载链接
VMware WorkStation Pro 秘钥地址。秘钥地址

2018.11.25 周日
今天把 VMware 安装完成了,因为 MacOS、Ubuntu、CentOS 的 ISO(镜像文件)还没有下载好,所以要等这几个镜像文件下载好之后才能进行下一步的学习。现在就做点其他的事情。

2018.11.26 周一
跟着教程用 .dmg 文件制作启动U盘然后安装MacOS系统失败,现在正在下载 .cdr 文件。Ubuntu 和 CentOS 安装成功。
MacOS 终于安装成功了,一共花了快两天的时间,不容易啊!总结一下安装步骤:

  1. 安装好 VMware WorkStation Pro,然后下载 unlocker 解锁 MacOS 安装选项;
  2. 下载 MacOS .cdr 文件,.dmg 文件没法在虚拟机中直接安装;
  3. 安装好 MacOS 之后,然后安装 darwin,使得虚拟机与主机可以拖拽文件等等;

2018.11.27 周二
今天在 Ubuntu 16.04 LTS 中安装了 GUI IDE 开发软件 – Visual Studio Code,安装过程很简单,百度就行。重点是在安装完之后还需要配置 C/C++ 开发环境,这个是一个全新的东西。配置C/C++开发环境在这里有两个事情需要做:1.在 Debug 中配置调试工具 gdb;2.在 Run Tasks 中新建 build 任务(编译、链接),一个 build 任务对应一个工程文件,负责对 .cpp 文件进行编译和链接,生成可执行文件。

2018.11.28 周三
今天学习了 Socket 的基础 API 接口(TCP 篇),分为客户端服务器端

  1. 客户端 API 接口:
    1.Socket – 申请和服务器端进行通信时必要的资源;
    2.connect – 通过 IP 地址和端口 Port 找到服务器进行连接;
    3.send – 向服务器发送数据,就像是使用 fwrite() 函数;
    4.recv – 接收服务器端发送来的数据,就像是使用 fread() 函数;
    5.closesocket – 关闭本次通信;

  2. 服务器端 API 接口:
    1.socket – 也是申请通信时需要的资源;
    2.bind – 申请一个 Port 用于 Socket 服务;
    3.listen – 启动端口监听模式;
    4.accept – 等待客户端的连接;
    5.recv – 接收客户端数据;
    6.send – 向客户端发送数据;
    7.closesocket – 关闭本次通信;

2018.11.29 周四
学习了Windows 环境下 Socket 编程的基本代码:

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <WinSock2.h>

#pragma comment(lib,"ws2_32.lib")	// 添加需要的静态链接库;

using namespace std;

int main()
{
	WORD ver = MAKEWORD(2, 2);	// Windows Socket 的版本号;
	WSADATA data;
	WSAStartup(ver,&data);	// 启动 Windows Socket 网络环境;
	///
		待添加操作;
	///
	WSACleanup();			// 关闭 Windows Socket 网络环境;
	return 0;
}

在写代码的过程中,学到了2个新的知识点

  1. <WinSock2.h> 和 <Windows.h> 会出现宏重定义,原因是因为 <Windows.h> 中包含了早期的 <winsock.h>,所以在包含 <WinSock2.h> 之后会出现宏重定义。
    解决办法有2个:
    1.#include <WinSock2.h> 之后再 #include <Windows.h>;
    2.使用宏定义:#define WIN32_LEAN_AND_MEAN;
  2. 添加需要的静态库:
    第一种方法,Windows环境下: #progma comment(lib, “ws2_32.lib”),这种代码不具有可移植性;
    第二种方法:在项目->属性->链接器->输入->附加依赖项中,添加所需要的静态库;

2018.11.30 周五
今天写了一个简易的 Server,使用了前边说的建立一个 server 需要使用的几个基本步骤。感觉在 Windows 下编写 server 有点怪怪的。使用了一些被包装的函数,而这些函数又没在前边提到过,有点晕。

2018.12.1 周六
用 Socket API 4步建立一个简易的客户端。
_getch(),在 <conio.h> 中,从控制台读取一个字符,但不显示在屏幕上。利用这个特性可以让程序暂停,直到用户按下一个按键。

2018.12.2 周日
今天回顾了昨天和前天做的笔记。
在原有的 server 和 client 程序的基础上,增加了 client 读取用户输入的命令,然后发送给 server,server 再返回预先设定好的数据的功能。使得程序成为一个可以持续处理请求的 C/S 网络程序。

2018.12.3 周一
之前一直苦恼不能用 SourceTree 上传文件夹到 GitHub,今天学会了使用 git 上传本地文件夹到 GitHub 的方法:

  1. 先将一个本地目录制作成本地 git 仓库:
    git init

  2. 暂存要 push 的文件:

git add .                // 暂存当前目录下的所有文件
git add main.cpp         // 暂存 main.cpp
  1. 为本次 commit 附加说明:
git commit -m "explanation"
  1. 将本地库与远程库关联:
git remote add origin "SSH链接"

如果出现错误:fatal: remote origin already exists,则执行:
git remote rm origin

  1. push 本次更改:
git push origin master

如果出现错误:failed to push som refs to…….,则执行以下语句:
git pull origin master --allow-unrelated-histories,先把远程服务器github上面的文件拉先来,再push 上去。

2018.12.4 周二
之前Client和Server之间传输的是字符串,今天将传输的数据修改成了一个简单的结构化数据:

struct{
  int age;
  char name[32];
};

2018.12.5 周三
将简单的结构化数据,升级为一个简单的报文数据,分为报文首部和数据部分。首部用于指出要执行的操作类型,数据部分的长度。数据部分是与相关操作类型对应的数据。报文首部和数据部分是分为两次发送,先发送首部,再发送数据部分。

2018.12.6 周四
将 Server 升级为使用 select 网络模型的简单版本。

2018.12.7 周五
测试使用 select 网络模型的 Server 与 Client 的通信。发现了一个错误,如下:

for (size_t i = g_clients.size() - 1; i >= 0; i--)
{
	// 将建立连接的客户端 socket 加入到 fdRead 中
	FD_SET(g_clients[i], &fdRead);
}

在测试时,这段代码提示 vector subscript 错误。经检查发现是因为:size_t 类型是 usigned int(无符号数),当 i = 0 时,i-- 得到的是一个最大的 usigned int 类型的正整数 64/32 位全1(而不是预料中的 -1),使得 vector 下标访问越界。
更正后代码:

for (int i = (int)g_clients.size() - 1; i >= 0; i--)
{
	// 将建立连接的客户端加入到 fdRead 中
	FD_SET(g_clients[i], &fdRead);
}

2018.12.8 周六
将 Client 升级成使用 select 网络模型,实现了当一个新的客户端加入时,其他的客户端会收到消息,说有新的客户端加入。

2018.12.9 周日
加了一些注释,主要是自己对 select 函数、fd_set 等的理解,将 Client 的 select 模型完善了,能像 Server 一样,在没有数据传输过来的时候,处理一些其他事务。
在 Client 中加入了一条新的线程 t1,使得 Client 恢复了从控制台读取用户输入的能力。在加入线程时有两点注意,因为主线程可能比 t1 早结束,所以,1.将 t1 与主线程分离,t1.detach();2.如果没有分离,那么在主线程的结尾处加上 t1.join(),让主线程等 t1 执行结束之后,再结束。

2018.12.10 周一
将 Client 移植到了 Linux 平台,并且能成功与 Windows 上的 Server 通信。接下来准备将 Client 移植到 MacOS 平台。

2018.12.11 周二
无。

2018.12.12 周三
今天到公司入职(Tieto)报到,然后补基础。今天就没有做项目,会调整时间,平衡工作与项目。

2018.12.13 周四
因为在公司实习的项目是关于移动通信的,所以这个引擎项目我会暂停一会儿,等把熟悉的实习工作之后再继续做。

猜你喜欢

转载自blog.csdn.net/u011499443/article/details/84259044