Skip to content

Saturday, 14 September 2024

Akademy is this yearly thing where bunch of KDE people go to talk about and work on KDE software. I had never been in one before, but this year I managed to make it there! This year Akademy was held at the city of Würzburg. This was also my first time in Germany, which is the furthest I've ever been from home.

I also had my wife Jenny with me, since if I had gone alone I would have gotten lost in some random mountain somewhere, or started a new life at the dark corners of Frankfurt airport, completely confused.

Friday, the day of flying (or so I thought)

On Friday the 6th, we left from Oulu to Helsinki first. Hop on plane at 14.30 and- Oh, a small delay.

Eh, it's fine, we hopped on the plane at 16.00 and-...

The flight was canceled.

So, we wait til like 19.30 or something to get to Helsinki. But of course, our flight from Helsinki to Germany had already left! No worries though, the next flight to Germany would leave soon.

Wait, what do you mean it leaves at 7.00?

Aaaaaaaaaahhhhggggggggggg....

Well, we got paid airport hotel room with paid dinner and breakfast. So we slept at Helsinki the first night. We were supposed to be at Würzburg at 23.55 or something, but of course not. Oh well, with some effort I might be able to make to the event, although I would miss the first few talks.

I had the most saddest (but still good) slab of lasagne at very sad and empty airport hotel restaurant. Very frustrated by everything. Sure it'll get better, right?

Saturday, the day of sleep deprivation

This time the airplane actually started to fly, instead of getting canceled for scandalous airplane activities, and we were on route to Frankfurt pretty soon. I spent some time in the airplane just working on my never-ending game project.

At Frankfurt, we got our luggage and went to the funny ICE train, which was a bit late. Apparently being late is some German train thing, I don't really understand it, but we have similar thing at Finland so it wasn't that shocking.

At the train, we were exhausted with our 4h of sleep due to stress not allowing us to sleep, so we just find some seats and sit down. Five minutes later some chap tells us to go away, so we stay up standing for the next 1h 30min next to the exit doors in some midcabin thing.

I wanted to watch some of the Akademy streams at this point, but I was mostly focusing on staying up.

Eventually, we finally reach the Burg of Würz. First impressions were that it looks really nice and.. What the hell is that? A.. mountain? Wow, they can be THAT tall??? (Authors note: Finland is very, VERY flat).

Also it was hellishly hot. The most I saw was 32 celsius. It was painful, I was sweating all the time and it was not fun.

We walk to our hotel room at Mercure hotel, which was really nice by the way. At this time, Akademy was having an incredible luncheon together, so me and Jenny decided to find something to eat. We found this place that was all about avocados, and I had something called powerbowl, which was brilliant.

After that, we began to study the incredibly complex thing that is the German bus system and started our trip towards the Akademy venue.

Aktually at Akademy

Me and my blurry sleep deprived brain walk to the venue and first off I meet familiar people. A lot of familiar people. Many hugs and "Oh you finally made it!"-s were shared. Jenny was with me there as well and it was fun to introduce her to my friends.

I honestly don't remember much about the day. It was quite a blur. But it was cool and I talked a lot.

I stole a lot of stickers and listened some talks, which I can barely remember... But I do remember which ones:

  • Arjen's talk about Union KDE styling theme thing, that is super cool.
  • Harald talked about of our own new possible shiny OS called KDE OS. Or 🍌 OS. I found this really exciting.
  • A lot of lighting talks, where Nicole's talk about teaching lil kiddos how to install Linux with KDE software on old PC's to bring them back alive.
    • I think this talk was my favorite. It was very wholesome, motivating and I'd like to have similar kind of teaching event at home. No promises, but.. Maybe!

During this day I also began to give out salmiakki to people, since I had been well prepared. It was kinda fun to see peoples reactions, especially if they had never heard of it before.

Then it was back to sleep at the hotel.

Sunday, I managed to do things

On sunday I was at Akademy pretty much the whole day. Again, I listened bunch of talks, met more people and we had many good chats about LTS distros, KDE PIM, Kwin, Flatpak... And many other things I can't remember.

I listened Carl's KDE Apps Initiative talk which was very motivating for me, since I've wanted to make a KDE app for a while. A gaming related lil thing.

After the fun group photo and delicious lunch, I chatted more and wandered about the venue.

There was a talk about daily driving Plasma Mobile and I found it very cool, and we had a chat about the Plasma Mobile afterwards. Apparently my Fairphone 5 could run PostmarketOS with Plasma Mobile pretty well already, but I am not yet ready to commit to such a change with my mobile device.

Last I listened Xaver's talk about what color is in computers. I learned that sRGB is a lie and gasped audibly, then heard a lot of words related to color systems I didn't really always understand.. But I found the talk still quite interesting and informative.

The evening was then again a bit of a blur, with sponsors lightning talks and Akademy Awards (congrats to winners btw).

Very interesting day, but I've always been bad when it comes to learning from listening. I learn by doing.

Of course the day wasn't complete without me going to wait bus with my t-shirt and shorts (since it was hot again), and it started pouring like heck. I was soaked when I got to the bus, then at the last stop I had to walk 1km to the hotel in the rain. Ah well, it was warm so I didn't mind too much.

Monday, I skipped the class

On monday I was so exhausted by Everything:tm: I decided to just chill with my wife and we went around Würzburg, buying food and chocolate.

I spent that day just recharging my social batteries. And I ate some Flammenkuchen, which was delicious!

At some point when Jenny is done editing and uploading her video, I will make separate post for it. Then you can see what Würzburg is like, and hear what she did during the trip.

Edit: Am lazy but heres the link to the video: https://www.youtube.com/watch?v=05qexeiHNeY

Tuesday, I flocked together with the birds

Like on monday, on tuesday as well Akademy had these events called "BoFs" which is abbreviation of Birds of a Feather. Because "Birds of a Feather Flock Together". I don't know why it's called that, but anyhow, I participated a few of them:

  • New design system bof
    • Very interesting discussions and ideas even I know nothing about design
    • I was mostly hoping to help people there with my programmer side of knowhow, as someone who has touched the Breeze styles codebases
  • Tiling in kwin bof
    • We mulled over what we could do to make tiling in kwin even better
    • I have this mini task for myself where I try to make tiles split automatically when a window is dragged on top of the other
  • Fedora KDE bof
    • I was just mostly curious whats up with Fedora KDE at the moment
    • I also wanted to give my praise for Fedora KDE, it's been my daily driver for many months now and it's been really good
    • Couple of my friends use it too due to my recommendation and they're having good time gaming on it! :)

To wrap up the evening, I had a fancy dinner with my friends. What was quite a culture shock to me was that after 22.00 the streets were practically completely empty. It was eerily quiet. At home we would have had few drunks about making noise, but at Germany there was just.. Silence.

Wednesday, to home again

Due to having two lizards and them needing a petsitter, and said petsitter not being able to be there the whole week, we left a bit early so we missed the daytrip and the last bof day.

Bit early being our flight from Frankfurt was leaving around 7.00. So we woke up at 5.00.

And when I wake up I saw a message in my phone saying: "Hi your flight is canceled"

Ah. Fun. If all had gone to plan, we would've been at home around 17.00. But instead, we were home at ~2.00.

We had to live at Frankfurt airport for ~7 hours, saw a lot of police with weapons (it was really scary to me, I've never seen weaponry like.. that openly), there was some suspicious luggage that got a whole McDonalds covered in "dont go here" tape and more police.

Urghgfhklfg. Scary.

Eventually we luckily made it to Helsinki and then back to Oulu and I didn't need to type out this blogpost from some corner of the airport.

Conclusions

Akademy was really fun event. I can hardly describe how fun it was. It's been quite a blur due to traveling issues and thus me being completely stressed and exhausted, but I still had many fun chats with everyone.

It was really nice to finally see who the people behind the internet names are and have talks with them, be it just random topics or KDE topics. I met people who I had never met before and shared many chats, laughs and information with them.

I learned quite a lot about what's going on in our KDE ecosystem and even outside of it, how we all interact. But I think the biggest thing I learned was that events like Akademy are crucial for the motivation and wellbeing of the KDE community. It helps us stay together, keep our bonds strong, be it KDE folk itself or people working with us, and keep us being awesome at what we do: Making computers do cool things, for free, for productivity and for fun.

Sorry about no photos, I have basically nothing: I am very bad at taking photos because I simply don't remember.

I love KDE and if you love KDE too, and if it's at all possible, visiting Akademy is well worth it!

See you at the next one, and apologies for the all-over-the-place-rambly-travel-post. Hope you find it a good read anyway.

Thanks for reading!

This year I went to Würzburg, which is a nice small German city famous for its wine. But I didn’t only go there for the wine, but also to attend Qt Contributor Summit and Akademy.

Qt Contributor Summit

The travel to Würzburg didn’t go as planned as Deutsch Bahn had some technical issues with their train and couldn’t reboot our train. We still managed to get in Würzburg on time and even had the change to get a small touristic tour from some locals.

Würzburg Residence and the Wine briget
Würzburg Residence and the Wine briget

The event itself was great and was the first time I attended fully a Qt Contributor Summit. Last year, I only attended a few session since the event was 20 min away from home.

There was many breakout rooms focused on some spcial topics, for me the most interesting sessions were about Qt for Python, how to hate QML, qt-project.org, Vector Graphics in Qt.

It was great to see how the KDE community still plays a big role in Qt and the Qt developers really appreciated what KDE finally moved to Qt6. They reported that the flow of contributors and bug reports increased.

Qt Chief Maintainer Volker Hilsheimer even stressed out how important it was for some of their customers to see KDE ported to Qt6, as it shows what Qt6 is stable and mature enough. Qt6 is indeed a hugo improvement over Qt5 and I am very happy how good the transition was.

Qt Contributor Summit
Qt Contributor Summit

I think it was a great idea to have Qt Contributor Summit just before Akademy. This allowed to have many KDE Contributor to the Qt Contributor Summit and many Qt developers to Akademy. It would be great next year to do the same next if possible and encourage more people from the Open Source Qt ecosystem to join too.

Akademy

Once the Qt Contributor Summit ended, we started a few hours later with the Akademy welcome event for some KDE beers. But before that, I had some bubble tea and spent some time with some friends exploring the city.

The weekend was full with a lot of great presentations. I presented a small report about the Accessibility Goal and the Fundraising working group. I also gave a bigger talk about the KDE Application Ecosystem, which I am really passionate about. The whole slides ware made with Calligra.

 

I was also very happy to see the new elected goals.

Sunday was also my birthday, thanks to everyone for congratulating me. I also received a super fancy special birthday sticker and some amazing cake.

Cake and stickers
Cake and stickers

Day Trip

We had our yearly day trip too, this time at Rothenburg ob der Tauber. A charming small town in south Germany.

Day trip Rothenburg ob der Tauber
Day trip Rothenburg ob der Tauber

BoFs

The next few days were filled with BoFs and many informal discussions. During the Promo BoF, we decided to create a “This Week in KDE Apps” blog posts. Paul volunteered Tobias, Joshua, and me as the initial team for this.

I also hosted a BoF about a future replacement of KWallet. There were some discussions about the scope of this effort. Should we just focus on storing OAuth2 tokens as a background service what the normal users should never interact with or do a full-blow password manager like macOS Keychain. I presented my work toward the latter around based on KeePassXC and the KeePass format (see my old blogpost) as it would allow to use a standardized file format that also work on other platforms. The KeePassXC developers are working on providing a reusable library, so we don’t need to fork their code. There will likely be more discussion about this in a separate gitlab issue. The lack of a good story around passwords is not unique to KDE but to the whole Linux ecosystem. If you have some opinions about this, feel free to reach out.

I discussed with Ben, Lydia and Aniqua the infrastructure for newsletters for our supporting members. Ben managed to get an instance of Listmonk in a matter of minutes and this seems to be the right way for us to manage a newsletters or at least way better than using a mailing list for this.

Kieryn hosted the best BoF: the Sticker BoF where we shared stickers and had a competition to see who had the best decorated laptop. I won!!! and received another special sticker. Thanks Kieryn for organizing this BoF and generally making Akademy this year such an awesome event!

Stickers
Stickers

I also ended up finishing a lot of work. I finally ported the last Drupal 7 website to Hugo: dot.kde.org which was a quite massive website with more than 20 years of history. I migrated the Hugo version used by KDE from 0.110.0 (which was more than a year old) to 0.134.0 and I am happy to report that the Hugo folks care a lot about stability and there was only some very small breaking changes. If you are working on some KDE websites, don’t forget to download the latest version of Hugo and to run the following command to update the KDE Hugo theme.

hugo mod get invent.kde.org/websites/hugo-kde@master

With Volker, we finally merged the status bar integration for Android apps so that KDE apps running on Android and now use breeze colors in their status bar, which looks much more integrated and like on Plasma Mobile.

Itinerary on Android with the new statubar
Itinerary on Android with the new statubar

I also got some improvements ideas during Akademy, and I already started implementing some of them: https://invent.kde.org/pim/itinerary/-/merge_requests/324

Finally I started rewritting the Calligra launcher to Kirigami based on the old Gemini UI. Still a bit far away from a being in a mergable state but it already looks quite good.

Calligra text document templates selection
Calligra text document templates selection

Calligra new document
Calligra new document

Conclusion

This was a great Akademy again. Thanks a lot for all the organizers for all their work. I hope to see some KDE contributors again soon at the Nextcloud Conference and Matrix Summit both in Berlin this month. And to the Linux Days in Dornbirn.

Friday, 13 September 2024

If you're using Plasma/KWin 6 i suggest you disable the Morphing Popups effect, it has been removed for Plasma 6.2 https://invent.kde.org/plasma/kwin/-/commit/d6360cc4ce4e0d85862a4bb077b8b3dc55cd74a7 and on X11 at least it causes severe redraw issues with tooltips in Okular (and i would guess elsewhere).

“Heather, Heather, Heather; what did you do now!” and both me & Fenris started laughing with Till, as we’re discussing about the thunderbird snap during the conference dinner.

Yup, this is from UbuCon Asia, my

  • First conference
  • First flight journey
  • First travel out of my state
  • First solo travel out of my state
  • First solo stay at a hotel

Huhhh, a lot of first timers! I can’t think actually where to start with… I met so many people out there, got so many mentors! Thanks Till , for introducing me with so many mentors! I met Guruprasad sir (the launchpad guru 😄), Kierthana mam and Dimple didi (both are the documentation gurus). A lot of suggestions, tips, guides from them! Thanks a lot 🥹! BTW, How can I forget my OG Bhavani bhaiyaa!

Akademy 2024 in Würzburg - it was a blast

My second Akademy and has ended just yesterday. It was an amazing and productive time again! Apart from familiar faces I know from last year’s Akademy or the Plasma sprint last year in Augsburg, I met plenty of new faces. Some of which I of course had contact in KDE before, but only in the digital world.

One of the best parts was again the day trip with the KDE Community. While it was a bit rainy, we for sure made the best of it and saw the beautiful city of “Rothenburg ob der Tauber”. The view from the town hall tower was very beautiful:

The talks were also quite interesting and highlighted how many facades the KDE Community has. Apart from the lightning talks being great again, the “QML in Qt6” talk was quite valuable, because I did not manage to follow up closely on the latest improvements.
The talks and BOFs related to the KDE goals were also quite beneficial in getting a good impression in what direction we want to go.

Since we had so many interesting talks, it was not possible to join all of them. What I will follow up on later are the talks “Pythonizing Qt” and “C++, Rust and Qt: Easier than you think”.

Albert Astals Cid and I gave a lightning talk together about JSON linting (my part) and QML linting (his part). We were only able to touch the surface in the given time, but had some productive discussions and follow-up questions afterward. I will create a post about the JSON validation/JSON schema topic in the future, since I am still working on some aspects of this.

It has been great again to also do some hacking together and discuss ideas in-person. I will miss being able to say “Let’s discuss this at Akademy?” on merge requests ;).
I did quite a bit of hacking on KRunner, linting/formatting related tooling and also Clazy.
This can also be seen on my GitLab history that has turned a bit more blue and thus active:
GitLab activity

What was a great improvement over the last Akademy were the chicken noises to make sure people stay within the time of their talk! To better improve on that, we should maybe get some real chicken next year 🥚🐣🐔. The talks on how to apply for funding in KDE might contain useful info when working towards this ;) PS: My life-long profile picture on GitHub/GitLab is of the super cute chicken I had 🥰.

Chicken picture

Thursday, 12 September 2024

I reverted my name back to Jonathan Riddell and have now made a new uid for my PGP key, you can get the updated one on keyserver.ubuntu.com or my contact page or my Launchpad page.

Here’s some pics from Akademy

KDE Akademy is meeting this week in Würzburg.

We just had a BoF session where we discussed..

  • The current progress to rebasing on Ubuntu 24.04
  • The current state of KDE neon Core our amazing forthcoming Snap based distro
  • Fixing up broken and bitrotting infrastructure
  • Moving to KDE invent
  • Issues with Plasma 6 upgrades and looking at integrating more QA tests
  • How the proposed KDE LinuxTM distro fits into the mix

Saturday, 27 July 2024

Future 聊天室

功能

账号管理

  • 实现登录、注册、注销
  • 实现找回密码(提高)

好友管理

  • 实现好友的添加、删除、查询操作
  • 实现显示好友在线状态
  • 禁止不存在好友关系的用户间的私聊
  • 实现屏蔽好友消息
  • 实现好友间聊天

群管理

  • 实现群组的创建、解散
  • 实现用户申请加入群组
  • 实现用户查看已加入的群组
  • 实现群组成员退出已加入的群组
  • 实现群组成员查看群组成员列表
  • 实现群主对群组管理员的添加和删除
  • 实现群组管理员批准用户加入群组
  • 实现群组管理员/群主从群组中移除用户
  • 实现群组内聊天功能

聊天功能

  • 实现查看历史消息记录
  • 实现用户间在线聊天
  • 实现在线用户对离线用户发送消息,离线用户上线后获得通知
  • 实现在线发送文件
  • 实现在线用户对离线用户发送文件,离线用户上线后获得通知/接收
  • 实现后台发送文件
  • 实现用户在线时,消息的实时通知
    • 收到好友请求
    • 收到私聊
    • 收到加群申请

其他

  • 使用 C++编程语言
  • 使用 I/O 多路复用完成本项目
    • C++:Epoll ET 模式
  • 使用数据库完成数据存储
    • Redis 和 mysql
    • 历史消息采用redis做告诉缓存,mysql来存储大量历史消息
  • 数据库中数据的存储和取用使用序列化和反序列化完成(Json)
  • 支持大量客户端同时访问
  • 实现服务器日志,记录服务器的状态信息
  • C/S 双端均支持在 CLI/Web 自行指定 IP:Port
  • 实现具有高稳定性的客户端和服务器,防止在用户非法输入时崩溃或异常
    • 实现 TCP 心跳检测

遇到的问题

  • 在客户端因某些原因异常退出时,服务端将无法正常处理其他请求.

    • 开始时服务端没有将新连接的描述符设置为非阻塞模式,导致客户端异常退出时服务端的接收recv一直在阻塞着读取,且无法处理其他请求
  • 如何往线程池中传入成员函数.

    • auto task = [](){     类的成员函数 } m_pool.submit(task);
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30

      * `Tcp`传输为字节流传输,采用在每条消息前面加上`长度`来正确接收每条请求.
      * 在代码中往`redis`数据库中添加好友申请数据时,没有正确插入.
      * 由于好友申请当中包含时间,姓名等信息,中间含有**空格**,在redis的哈希表中无法插入.
      * 经过查阅在redis哈希表中,**空格**可以用`+`代替,在遇到`+`时会被转义为**空格**,或者存储为**十六进制**,但是这种方法在终端中的**空格**为灰色.

      * 在聊天界面如果输入带有`%`,服务器直接挂掉.

      * ```c++
      int redisAsyncContext::Lpush(const std::string &key, const std::string &value)
      {
      //std::string cmd = "lpush " + key + " " + value;
      this->m_reply = (redisReply *)redisCommand(this->m_connettion, "LPUSH %s %s", key.c_str(), value.c_str());
      // 检查 m_reply 是否为 NULL
      if (this->m_reply == NULL) {
      std::cerr << "Error: redisCommand returned NULL" << std::endl;
      return -1; // 或其他合适的错误值
      }

      // 检查 m_reply 类型
      if (this->m_reply->type != REDIS_REPLY_INTEGER) {
      std::cerr << "Error: Expected integer reply" << std::endl;
      freeReplyObject(this->m_reply);
      return -1; // 或其他合适的错误值
      }
      int num = this->m_reply->integer;
      freeReplyObject(this->m_reply);
      std::cout << "G" << std::endl;
      return num;
      }
    • 在执行下面两句是,%会被替换为cmd.c_str(),导致无法将消息插入历史记录表,导致出现错误.

      1
      2
      std::string cmd = "lpush " + key + " " + value;
      this->m_reply = (redisReply *)redisCommand(this->m_connettion, cmd.c_str());
    • 只要更改为下面即没有问题

      1
      this->m_reply = (redisReply *)redisCommand(this->m_connettion, "LPUSH %s %s", key.c_str(), value.c_str());
  • 在某次测试时,新注册账号id为0614897828,导致与该账号聊天的账号进入聊天界面时,0614897828发送的消息会在他人界面显示为通知消息.

    • 由于与人聊天时会在数据库中创建有排序集合来记录某人正在聊天的人的id.运行时通过查看发现,其余账号与0614897828聊天时,数据库中记录账号为614897828.
    • 更换为首位非0的id就不会出现该问题.
    • redis会将有序集合中的score字段字符串中的0去除.将从字符串的首位非0开始存储.
  • 在进入好友私聊界面时,客户端新建了来接收消息,同时主线程发消息,主线程通过判断用户是否键入Esc来退出聊天界面,在输入Esc时,接收消息线程无法正确回收,无法退出聊天界面.

    • 在接收消息线程中来判断标志位来结束该线程,主线程在键入Esc时,将标志位设置为false,但由于客户端的recv为阻塞,导致无法及时获取到标志位的更改.
    • 在键入Esc时,服务器向客户端发送退出信号,这样就可以正确及时的获取到标志位的更改,从而正确退出.
  • 在进行发送文件时,服务器会先将文件存储在本地,但是服务器存储的文件会多写入一些信息,导致接收文件大小偏大.

    • 由于在用户登陆进入之后,会有一个线程每5秒向服务器送送刷新请求,导致服务器会将刷新请求当作文件内容写入文件,导致接收文件不一致
    • 在进入文件收发菜单后,关闭实时刷新,在文件结束后,再将实时刷新打开.
  • 实现后台发送文件,由于会有实时刷新的存在,会导致文件发送不准确.

    • 在发送文件时,重新创建一个socket连接到服务器,在将发送这个文件交给另外一个线程
    • 初始时在用户选择发送文件时开始线程,但会导致主线程与发送线程会同时运行菜单.主线程继续循环菜单,而发送线程运行获取发送文件的信息。
      • 更改线程开始时间,在用户选择发送文件时,获取到发送文件信息后,在启动线程.
      • 新连接的socket发送文件后,服务器不用手动断开连接,服务器有心跳检测,会在一段时间后断开.

eventfd

详解

是一个Linux系统调用,也是一种进程间通信(IPC)机制,主要通过使用文件描述符生成和使用事件通知.

提供了一种在不同进程之间或同一进程内的线程之间的同步事件的方法.

异常处理

异常是程序在执行期间产生的问题。c++异常是指在程序运行时发生的特殊情况.

异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字:try、catch、throw

关键字:try、catch、throw

  • throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
  • catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常

  • try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块

1
2
3
4
5
6
7
8
9
10
11
12
13
try
{
// 保护代码
}catch( ExceptionName e1 )
{
// catch 块
}catch( ExceptionName e2 )
{
// catch 块
}catch( ExceptionName eN )
{
// catch 块
}

nlohmann::json

链接

SIGPIPE

SIGPIPE 是一种信号,当一个进程尝试向一个已经关闭的或不可写的管道或套接字写数据时,会触发这个信号。默认情况下,接收到 SIGPIPE 信号的进程会终止。这在网络编程中会导致一些问题,因为如果客户端断开连接,服务器进程在写入数据时会因为这个信号而意外退出。

在网络编程中,特别是使用套接字进行通信时,忽略 SIGPIPE 信号是一个常见的做法。这样可以防止进程因为 SIGPIPE 信号而意外终止。相反,程序可以通过检测 sendwrite 操作的返回值来处理错误,从而使程序更加健壮。

后续问题

  1. 初始客户端构思方面的缺陷,导致实时消息没有线程及时接收。

    当前处理方式为服务端将通知消息放入数据库当中,客户端在登陆之后,增加一个线程来定时执行刷新函数,刷新数据库中的通知消息

    可以优化为在客户端登陆之后,采用多线程的方式来处理相关操作.

  2. 目前只有在历史消息这一操作涉及到redis+mysql的处理方式.

    可以将一些重要信息也采用redis+mysql的处理方式(涉及到redis的存储方式,redis存储于内存当中,会造成数据丢失的情况)

    可以考虑将redis全部做为缓存的形式,将重要信息与历史消息类似,达到一定情况下放入mysql,使数据更加的持久化.

后续学习

  1. 继续学习epoll的相关内容.

  2. 了解其余网络框架,使得该项目的服务端更加的健壮.

  3. 了解消息队列的信息同步的问题.

  4. 熟悉零拷贝的过程,以及零拷贝的具体实现.

  5. 序列化的相关协议,json与其他序列化的区别、json的优点,以及为什么不用其他的序列化

  6. 数据库的深入学习,了解redis的缓存穿透、缓存雪崩、缓存击穿。加强对mysql数据库的学习.

  7. 加强对网络协议相关知识的学习.

Friday, 17 May 2024

强制类型转换

C++提供了四个强制类型转换的关键字:

  • static_cast
  • const_cast
  • reinterpret_cast
  • ``dynamic_cast`

static_cast

1
static_cast<目标类型>(表达式)
1
2
int num = 2;
double result =static_cast<double>(num);

该运算符将表达式转换为目标类型。但没有进行运行时类型检查来保证转换的安全性

主要用法

  1. 用于类层次结构中父类和子类之间指针或引用的转换.进行上行转换是安全的(即将子类的指针或引用转换成父类是正确的);进行下行转换的时候,由于没有动态类型检查,所以是不安全的。继承必须为public
  2. 用于基本类型之间的转换,如intchar安全性也需要程序员来保证
  3. 把空指针转换为目标类型的空指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Person
{
public:
void print()
{
cout << "Person " << endl;
}
};

class Son : public Person
{
public:
void print()
{
cout << "Son " << endl;
}
};

void print1(Person *p)
{
p->print();
}

int main()
{
Son s;
print1(static_cast<Person *>(&s));
return 0;
}

const_cast

const_cast是c++中专用于处理与const相关的强制类型转换的关键字

其功能为:为一个变量重新设定其const描述.

即:const_cast可以为一个变量强行增加或删除其const限定.

需要明确的是,即使用户通过const_cast强行去除了const属性,也不代表当前变量从不可变变为了可变。const_cast只是使得用户接管了编译器对于const限定的管理权,故用户必须遵守“不修改变量”的承诺。如果违反此承诺,编译器也不会因此而引发编译时错误,但可能引发运行时错误。

  1. const_cast可用于更改const成员函数内的非const类成员。
  2. const_cast可用于将const数据传递给不接收const的函数。
  3. const_cast<>里边的内容必须是引用或者指针。
  4. const_cast也可以用来抛弃volatile__unaligned属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Student
{
private:
int roll;
public:
Student(int r) :roll(r) {}
void fun() const
{
(const_cast<Student*> (this))->roll = 5;
}
int getRoll() { return roll; }
};

int main() {
Student student(3);
std::cout << "Old roll number: " << student.getRoll() << std::endl;
student.fun();
std::cout << "New roll number: " << student.getRoll() << std::endl;

// const_cast只能调节类型限定符,不能更改基础类型
int a1 = 40;
//const int* b1 = &a1;
//char* c1 = const_cast <char*> (b1); // 编译程序时出错

const volatile int* d1 = &a1;
std::cout << "typeid of d1 " << typeid(d1).name() << '\n'; // int const volatile *
int* e1 = const_cast <int*> (d1);
std::cout << "typeid of e1 " << typeid(e1).name() << '\n'; // int *

return 0;
}

在const成员函数fun()中,编译器将“this”视为“ const student const this”,即“this”是指向常量对象的常量指针,因此编译器不允许通过以下方式更改数据成员“这个”指针。const_cast将“this”指针的类型更改为“student const this”

const_cast比简单类型转换更安全。从某种意义上讲,如果强制类型与原始对象不相同,则强制转换不会发生,这是比较安全的。

1
2
3
int a=20;
const int *p=&a;
char *c1=const_cast<char*> (p);//编译时程序出错

reinterpret_cast

reinterpret,即重新解释.

该强制类型转换的作用是提供某个变量在底层数据上的重新解释.

当我们对一个变量使用reinterpret_cast后,编译器将无视任何不合理行为,强行将被转换变量的内存数据重解释为某个新的类型。用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换。转换时,执行的是逐个比特复制的操作。 它不检查指针类型和指针所指向的数据是否相同。

需要注意的是,reinterpret_cast要求转换的两个数据所占用的内存大小一致,否则会引发编译时错误.

1
data_type *var_name = reinterpret_cast <data_type *>(pointer_variable);

使用 reinterpret_cast 的目的:

  1. reinterpret_cast是一种非常特殊且危险的类型转换操作符。并且建议使用适当的数据类型使用它,即(指针数据类型应与原始数据类型相同)。
  2. 它可以将任何指针类型转换为任何其他数据类型。
  3. 当我们要使用位时使用它。
  4. 它仅用于将任何指针转换为原始类型。
  5. 布尔值将转换为整数值,即0表示false,1表示true。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class A {
public:
int a;
A(int i) :a(i) {}
void fun_a()
{
std::cout << "In class A\n";
}
};

class B {
public:
int b;
B(int i) :b(i) {}
void fun_b()
{
std::cout << "In class B\n";
}
};

void testReinterpretCast() {
B *x = new B(5);
A* y = reinterpret_cast<A*>(x);
y->fun_a(); // In class A
std::cout << y->a << std::endl; // 5
}

dynamic_cast

dynamic用于在运行时实现向下类型转换。

1
dynamic_cast <type-id> (expression)

expression转换为type-id类型,type-id必须是类的指针,类的引用或者是void,

如果type-id是一个指针,那么expression也是一个指针,是引用的话同为引用

特点如下:

  1. 它是在运行是进行处理的,其余三个都是在编译时完成. 运行时进行类型检查
  2. 不能用于内置的基本数据类型之间的强制转换
  3. dynamic_cast 要求 <> 内所描述的目标类型必须为指针或引用。dynamic_cast 转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回 nullptr
  4. 在类的转换时,在类层次上进行向上转换(子类指针指向父类指针),与static_cast的效果是一样的。在进行父类指针向子类指针的转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
  5. 向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。在C++中,编译期的类型转换有可能会在运行时出现错误,特别是涉及到类对象的指针或引用操作时,更容易产生错误。dynamic_cast操作符则可以在运行期对可能产生问题的类型转换进行测试。
  6. 使用 dynamic_cast 进行转换的,基类中一定要有虚函数,否则编译不通过(类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义)。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class AA {
public:
virtual void print() {
cout << "in class AA" << endl;
};
};

class BB :public AA {
public:
void print() {
cout << "in class BB" << endl;
};
};

void testDynamicCast() {
AA* a1 = new BB; // a1是A类型的指针指向一个B类型的对象
AA* a2 = new AA; // a2是A类型的指针指向一个A类型的对象

BB* b1, * b2, * b3, * b4;

b1 = dynamic_cast<BB*>(a1);// not null,向下转换成功,a1 之前指向的就是 B 类型的对象,所以可以转换成 B 类型的指针。
if (b1 == nullptr)
cout << "b1 is null" << endl;
else
cout << "b1 is not null" << endl;

b2 = dynamic_cast<BB*>(a2);// null,向下转换失败
if (b2 == nullptr)
cout << "b2 is null" << endl;
else
cout << "b2 is not null" << endl;

// 用 static_cast,Resharper C++ 会提示修改为 dynamic_cast
b3 = static_cast<BB*>(a1);// not null
if (b3 == nullptr)
cout << "b3 is null" << endl;
else
cout << "b3 is not null" << endl;

b4 = static_cast<BB*>(a2);// not null
if (b4 == nullptr)
cout << "b4 is null" << endl;
else
cout << "b4 is not null" << endl;

a1->print();// in class BB
a2->print();// in class AA

b1->print();// in class BB
//b2->print(); // null 引发异常
b3->print();// in class BB
b4->print();// in class AA
}

详细

Friday, 10 May 2024

Lambda表达式

匿名函数是很多高级语言都支持的概念,如lisp语言在1958年首先采用匿名函数。匿名函数有函数体,但没有函数名。C++11中引入了lambda表达式。利用lambda表达式可以编写内嵌的匿名函数,用以替换独立函数或者函数对象,并且使代码更可读。但是从本质上来讲,lambda表达式只是一种语法糖,因为所有其能完成的工作都可以用其它稍微复杂的代码来实现。但是它简便的语法却给C++带来了深远的影响。如果从广义上说,lamdba表达式产生的是函数对象。

相同类似功能我们也可以使用函数对象或者函数指针实现:函数对象能维护状态,但语法开销大,而函数指针语法开销小,却没法保存范围内的状态。lambda表达式正是结合了两者的优点。

声明Lambda表达式

1
2
3
4
5
6
7
// 完整语法
[capture list] (params list) mutable(optional) constexpr(optional)(c++17) exception attribute -> return type { function body };

// 可选的简化语法
[capture list] (params list) -> return type {function body}; //1
[capture list] (params list) {function body};//2
[capture list] {function body};//3
  • capture list:捕获外部变量列表,不能省略;
  • params list:形参列表,可以省略(但是后面必须紧跟函数体);
  • mutable指示符: 可选,将lambda表达式标记为mutable后,函数体就可以修改传值方式捕获的变量;
  • constexpr:可选,C++17,可以指定lambda表达式是一个常量函数;
  • exception:异常设定, 可选,指定lambda表达式可以抛出的异常;
  • attribute:可选,指定lambda表达式的特性;
  • return type:返回类型
  • function body:函数体

标号1. 函数声明了一个const类型的表达式,此声明不可改变capture list中的捕获的值。

标号2. 函数省略了返回值,此时如果function body内含有return语句,则按return语句返回类型决定返回值类型,若无则返回值为void类型。

标号3. 函数无参数列表,意味无参函数。

1
2
3
vector<int> vec{1,0,9,5,3,3,7,8,2};

sort(lbvec.begin(), lbvec.end(), [](int a, int b) -> bool { return a < b; });

捕获外部变量

lambda表达式最前面的方括号的意义何在?其实这是lambda表达式一个很Hong要的功能,就是闭包。这里我们先讲一下lambda表达式的大致原理:每当你定义一个lambda表达式后,编译器会自动生成一个匿名类(这个类当然重载了()运算符),我们称为闭包类型(closure type)。那么在运行时,这个lambda表达式就会返回一个匿名的闭包实例,其实一个右值。所以,我们上面的lambda表达式的结果就是一个个闭包。闭包的一个强大之处是其可以通过传值或者引用的方式捕捉其封装作用域内的变量,前面的方括号就是用来定义捕捉模式以及变量,我们又将其称为lambda捕捉块。

Lambda表达式可以捕获外面变量,但需要我们提供一个谓词函数([capture list]在声明表达式最前)。类似参数传递方式:值传递、引入传递、指针传递。在Lambda表达式中,外部变量捕获方式也类似:值捕获、引用捕获、隐式捕获

值捕获

1
2
3
4
5
int a = 123;
auto f = [a] { cout << a << endl; };
f(); // 输出:123
a = 321;
f(); // 输出:123

值捕获和参数传递中的值传递类似,被捕获的值在Lambda表达式创建时通过值拷贝的方式传入,类中会相应添加对应类型的非静态数据成员。在运行时,会用复制的值初始化这些成员变量,从而生成闭包。因此Lambda表达式函数体中不能修改该外部变量的值; 因为函数调用运算符的重载方法是const属性的。同样,函数体外对于值的修改也不会改变被捕获的值。 想改动传值方式捕获的值,那么就要使用mutable

1
2
3
auto add_x = [x](int a) mutable { x *= 2; return a + x; };  // 复制捕捉x

cout << add_x(10) << endl; // 输出:30

因为一旦将lambda表达式标记为mutable,那么实现的函数调用运算符是非const属性的。

引用捕获

1
2
3
4
int a = 123;
auto f = [&a] { cout << a << endl; };
a = 321;
f(); // 输出:321

引用捕获的变量使用的实际上就是该引用所绑定的对象,因此引用对象的改变会改变函数体内对该对象的引用的值。 对于引用捕获方式,无论是否标记mutable,都可以在lambda表达式中修改捕获的值。

隐式捕获

隐式捕获有两种方式,分别是 [=]:以值补获的方式捕获外部所有变量 [&]:表示以引用捕获的方式捕获外部所有变量

1
2
3
int a = 123, b=321;
auto df = [=] { cout << a << b << endl; }; // 值捕获
auto rf = [&] { cout << a << b << endl; }; // 引用捕获

其他

捕获外部变量形式
[ ]不捕获任何变量(无参函数)
[变量1,&变量2, …]值(引用)形式捕获指定的多个外部变量
[this]值捕获this指针
[=, &x]变量x以引用形式捕获,其余变量以传值形式捕获
[*this]通过传值方式捕获当前对象
[&, x]默认以引用捕获所有变量,但是x是例外,通过值捕获

既然只使用一次,那直接写全代码不就行了,为啥要函数呢?——因为lambda可以捕获局部变量

在上面的捕获方式中,注意最好不要使用[=][&]默认捕获所有变量。首先说默认引用捕获所有变量,你有很大可能会出现悬挂引用(Dangling references),因为引用捕获不会延长引用的变量的声明周期:

1
2
3
4
std::function<int(int)> add_x(int x)
{
return [&](int a) {return x+a;};
}

因为参数x仅是一个临时变量,函数调用后就被销毁,但是返回的lambda表达式却引用了该变量,但调用这个表达式时,引用的是一个垃圾值,所以会产生没有意义的结果。如果通过传值的方式来解决上面的问题:

1
2
3
4
std::function<int(int)> add_x(int x)
{
return [=](int a) { return x + a; };
}

使用默认传值方式可以便面悬挂引用问题.但是采用默认值捕获所有变量仍然有风险。例如当在类中捕获私有变量,当返回值为lambda表达式时,无法捕获到私有变量,但当指定为[=]时,会捕获到this指针的副本,当类已经调用析构函数,使用该指针仍然不安全.

参数

  • 参数列表中不能有默认参数
  • 不支持可变参数
  • 所有参数必须要参数名(相当于不可以有占位参数)

返回类型

单一的return语句可以推断返回类型;多语句则默认返回void,否则报错,应指定返回类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 正确,单一return语句
transform(vi.begin(),vi.end(),vi.begin(),
[] (int i) {
return i<0? -i; i;
}
);
// 错误。不能推断返回类型
transform(vi.begin(),vi.end(),vi.begin(),
[] (int i) {
if (I<0) return -i;
else return i;
}
);
// 正确,尾置返回类型
transform(vi.begin(),vi.end(),vi.begin(),
[] (int i) ->int{
if (I<0)
return -i;
else
return i;
}
);

赋值

auto和function可接受lambda表达式的返回:

1
2
3
int x =8,y=9;
auto add = [](int a,int b){return a+b;};
std::function<int(int,int)> Add = [=] (int a,int b){return a+b};

lambda表达式产生的类不含有默认构造函数、赋值运算符、默认析构函数。至于闭包类中是否有对应成员,C++标准中给出的答案是:不清楚的,看来与具体实现有关。还有一点要注意:lambda表达式是不能被赋值的:

1
2
3
4
5
auto a = [] { cout << "A" << endl; };
auto b = [] { cout << "B" << endl; };

a = b; // 非法,lambda无法赋值
auto c = a; // 合法,生成一个副本

因为禁用了赋值操作符:

1
ClosureType& operator=(const ClosureType&) = delete;

但是没有禁用复制构造函数,所以可以用一个lambda表达式去初始化另外一个lambda表达式而产生副本。并且lambda表达式也可以赋值给相对应的函数指针,这也使得你完全可以把lambda表达式看成对应函数类型的指针

新特性

C++14中,lambda又得到了增强,一个是泛型lambda表达式,一个是lambda可以捕捉表达式。

lambda捕捉表达式

lambda表达式可以按复制或者引用捕获在其作用域范围内的变量。而有时候,我们希望捕捉不在其作用域范围内的变量,而且最重要的是我们希望捕捉右值。所以C++14中引入了表达式捕捉,其允许用任何类型的表达式初始化捕捉的变量:

1
2
3
4
5
6
7
8
// 利用表达式捕获,可以更灵活地处理作用域内的变量
int x = 4;
auto y = [&r = x, x = x + 1] { r += 2; return x * x; }();
// 此时 x 更新为6,y 为25

// 直接用字面值初始化变量
auto z = [str = "string"]{ return str; }();
// 此时z是const char* 类型,存储字符串 string

可以看到捕捉表达式扩大了lambda表达式的捕捉能力,有时候你可以用std::move初始化变量。这对不能复制只能移动的对象很重要,比如std::unique_ptr,因为其不支持复制操作,你无法以值方式捕捉到它。但是利用lambda捕捉表达式,可以通过移动来捕捉它:

1
2
3
4
auto myPi = std::make_unique<double>(3.1415);

auto circle_area = [pi = std::move(myPi)](double r) { return *pi * r * r; };
cout << circle_area(1.0) << endl; // 3.1415

原文章