mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-03-03 01:10:13 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
ffc1e29080
@ -1,28 +1,28 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11968-1.html)
|
||||
[#]: subject: (How to set up your own fast, private open source mesh network)
|
||||
[#]: via: (https://opensource.com/article/20/2/mesh-network-freemesh)
|
||||
[#]: author: (Spencer Thomason https://opensource.com/users/spencerthomason)
|
||||
|
||||
如何建立自己的快速、私有的开源网状网络
|
||||
如何建立自己的快速、私有的开源网状网络(mesh)
|
||||
======
|
||||
|
||||
> 只需要不到 10 分钟的安装时间,就可以用 FreeMesh 搭建一个经济实惠、性能卓越、尊重隐私的网格系统。
|
||||
|
||||
![people on top of a connected globe][1]
|
||||

|
||||
|
||||
[FreeMesh][2] 系统有望为大众带来完全开源的<ruby>网格网络<rt>mesh network</rt></ruby>。我最近有机会进行了测试;它安装迅速,性能非常好 —— 特别是相对它的价格而言。
|
||||
[FreeMesh][2] 系统有望为大众带来完全开源的<ruby>网状网络<rt>mesh network</rt></ruby>(LCTT 译注:也称之为“多跳网络”)。我最近有机会对它进行了测试;它安装迅速,性能非常好 —— 特别是相对它的价格而言。
|
||||
|
||||
### 为什么要网格化和开源?
|
||||
|
||||
使用开源的原因很简单:隐私。有了 FreeMesh,你的数据就是你自己的。它不会跟踪或收集数据。不相信吗?毕竟,你可以轻松检查 —— 它是开源的!而其它大型高科技企业集团提供的一些流行的网格解决方案,你是否相信它们会保护你的数据?
|
||||
使用开源的原因很简单:隐私。有了 FreeMesh,你的数据就是你自己的。它不会跟踪或收集数据。不相信吗?毕竟,你可以轻松检查 —— 它是开源的!而其它大型高科技企业集团提供的一些流行的网状网络解决方案,你是否相信它们会保护你的数据?
|
||||
|
||||
另一个重要因素:更新。FreeMesh 表示,它将致力于定期发布安全性和性能更新。从现在起到 10 年后呢?使用开放源代码解决方案,你可以根据需要自由地更新产品。
|
||||
另一个重要因素:更新。FreeMesh 表示,它将致力于定期发布安全性和性能更新。从现在起到 10 年后呢?使用开源解决方案,你可以根据需要自由地更新产品。
|
||||
|
||||
那么为什么要用网格呢?在网状网络中,多个无线路由器一起工作以广播单个超大型的无线网络。网状网络中的每个路由器都可与其他路由器智能地通信,以便为你的数据提供最佳的“路径”。FreeMesh 网站上的以下图片突出显示了使用单个无线路由器和网状网络之间的区别。 红色网络表示单个无线路由器,绿色网络是网状网络。
|
||||
那么为什么要用网状网络呢?在网状网络中,多个无线路由器一起工作以广播单个超大型的无线网络。网状网络中的每个路由器都可与其他路由器智能地通信,以便为你的数据提供最佳的“路径”。FreeMesh 网站上的以下图片突出显示了使用单个无线路由器和网状网络之间的区别。红色网络表示单个无线路由器,绿色网络是网状网络。
|
||||
|
||||
![单路由器网络] [3]
|
||||
|
||||
@ -52,7 +52,7 @@ FreeMesh 路由器的一些规格非常好:
|
||||
|
||||
![FreeMesh 设置步骤 1][8]
|
||||
|
||||
2、等待约 30 至 60 秒。设置完成后,节点将闪烁其 LED。
|
||||
2、等待约 30 至 60 秒。设置完成后,节点的 LED 将会闪烁。
|
||||
|
||||
![FreeMesh 设置步骤 2][9]
|
||||
|
||||
@ -74,7 +74,7 @@ FreeMesh 是开箱即用的,它由 OpenWRT 和 LuCI 组合而成。它具有
|
||||
|
||||
设置完 FreeMesh 系统后,我将节点移动到了房屋周围的各个地方。我使用 [iPerf][13] 测试带宽,它达到了约 150Mbps。WiFi 可能会受到许多环境变量的影响,因此你的结果可能会有所不同。节点与主路由器之间的距离在带宽中也有很大的影响。
|
||||
|
||||
但是,网状网络的真正优势不是高峰速度,而是整个空间的平均速度要好得多。即使在我家很远的地方,我仍然能够流媒体播放视频并正常工作。我甚至可以在后院工作。在出门之前,我只是将一个节点重新放在窗口前面而已。
|
||||
但是,网状网络的真正优势不是高峰速度,而是整个空间的平均速度要好得多。即使在我家很远的地方,我仍然能够用流媒体播放视频并正常工作。我甚至可以在后院工作。在出门之前,我只是将一个节点重新放在窗口前面而已。
|
||||
|
||||
### 结论
|
||||
|
||||
@ -91,7 +91,7 @@ via: https://opensource.com/article/20/2/mesh-network-freemesh
|
||||
作者:[Spencer Thomason][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11967-1.html)
|
||||
[#]: subject: (PHP Development on Fedora with Eclipse)
|
||||
[#]: via: (https://fedoramagazine.org/php-development-on-fedora-with-eclipse/)
|
||||
[#]: author: (Mehdi Haghgoo https://fedoramagazine.org/author/powergame/)
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
![][1]
|
||||
|
||||
[Eclipse][2] 是由 Eclipse 基金会开发的功能全面的免费开源 IDE。自 2001 年以来一直存在。你可以在此 IDE 中编写从 C/C++ 和 Java 到 PHP、Python、HTML、JavaScript、Kotlin 等。
|
||||
[Eclipse][2] 是由 Eclipse 基金会开发的功能全面的自由开源 IDE。它诞生于 2001 年。你可以在此 IDE 中编写各种程序,从 C/C++ 和 Java 到 PHP,乃至于 Python、HTML、JavaScript、Kotlin 等等。
|
||||
|
||||
### 安装
|
||||
|
||||
@ -36,15 +36,15 @@ sudo dnf install eclipse-pdt
|
||||
|
||||
### 示例项目
|
||||
|
||||
现在已经安装了 IDE,让我们创建一个简单的 PHP 项目。进入 _File →New → Project_。在出现的对话框中,选择 _PHP project_。输入项目的名称。你可能还需要更改其他一些选项,例如更改项目的默认位置,启用 JavaScript 以及更改 PHP 版本。请看以下截图。
|
||||
现在已经安装了 IDE,让我们创建一个简单的 PHP 项目。进入 “File →New → Project”。在出现的对话框中,选择 “PHP project”。输入项目的名称。你可能还需要更改其他一些选项,例如更改项目的默认位置,启用 JavaScript 以及更改 PHP 版本。请看以下截图。
|
||||
|
||||
![Create A New PHP Project in Eclipse][3]
|
||||
|
||||
你可以单击 _Finish_ 按钮创建项目,或按 _Next_ 配置其他选项,例如添加包含和构建路径。在大多数情况下,你无需更改这些设置。
|
||||
你可以单击 “Finish” 按钮创建项目,或按 “Next” 配置其他选项,例如添加包含和构建路径。在大多数情况下,你无需更改这些设置。
|
||||
|
||||
创建项目后,右键单击项目文件夹,然后选择 _New→PHP File_ 将新的 PHP 文件添加到项目。在本教程中,我将其命名为 _index.php_,这是每个 PHP 项目中公认的默认文件。
|
||||
创建项目后,右键单击项目文件夹,然后选择 “New→PHP File” 将新的 PHP 文件添加到项目。在本教程中,我将其命名为 `index.php`,这是每个 PHP 项目中公认的默认文件。
|
||||
|
||||
![][4]
|
||||
![add a new PHP file][4]
|
||||
|
||||
接着在新文件中添加代码。
|
||||
|
||||
@ -52,9 +52,9 @@ sudo dnf install eclipse-pdt
|
||||
|
||||
在上面的例子中,我在同一页面上使用了 CSS、JavaScript 和 PHP 标记,主要是为了展示 IDE 能够支持所有这些标记。
|
||||
|
||||
页面完成后,你可以将文件移至 Web 服务器文档根目录或在项目目录中创建一个开发 PHP 服务器来查看输出。
|
||||
页面完成后,你可以将文件移至 Web 服务器文档根目录或在项目目录中创建一个 PHP 开发服务器来查看输出。
|
||||
|
||||
借助 Eclipse 中的内置终端,我们可以直接在 IDE 中启动 PHP 开发服务器。只需单击工具栏上的终端图标(![Terminal Icon][6]),然后单击 _OK_。在新终端中,进入项目目录,然后运行以下命令:
|
||||
借助 Eclipse 中的内置终端,我们可以直接在 IDE 中启动 PHP 开发服务器。只需单击工具栏上的终端图标(![Terminal Icon][6]),然后单击 “OK”。在新终端中,进入项目目录,然后运行以下命令:
|
||||
|
||||
```
|
||||
php -S localhost:8080 -t . index.php
|
||||
@ -73,7 +73,7 @@ via: https://fedoramagazine.org/php-development-on-fedora-with-eclipse/
|
||||
作者:[Mehdi Haghgoo][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,111 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How I learned about burnout the hard way)
|
||||
[#]: via: (https://opensource.com/article/20/3/burnout)
|
||||
[#]: author: (Jason Hibbets https://opensource.com/users/jhibbets)
|
||||
|
||||
How I learned about burnout the hard way
|
||||
======
|
||||
Burnout can happen to anyone. Here are the 3 things I wish I knew before
|
||||
I burned out.
|
||||
![Light bulb][1]
|
||||
|
||||
In early 2017, I was mentally in a bad spot. It was the perfect storm of stress, the kind that no one asks for, but you deal with the hand you're dealt. Work was piling up to a point where I couldn't process all the things that were expected of me. I was training for spring half-marathons, which should have been stress relief, but I was putting too much pressure on myself to perform at a high level. And then on top of the everyday family obligations, a surgery in our household turned us into a one-car family and seriously added to the mounting pressure on me to provide and take care of the family.
|
||||
|
||||
Then I broke.
|
||||
|
||||
It wasn't one thing. It was the culmination of things. And it hit me from the blind side, unexpected. I never thought I would be a victim of burnout. I was aware of it and thoughtful about the community I was managing. But "not me," I thought to myself, "I've got this under control." I remember thinking that something was wrong; something was off. But I couldn't quite put my finger on the source.
|
||||
|
||||
I distinctly remember the day where I cried at work, crumbling under the pressure that I was putting on myself. I consider myself a high performer in the office environment. I push myself to exceed the goals that my team co-creates because I want that success. I want the feeling that comes with it. But this experience was different. This wasn't a healthy win for my team or me. I felt like I let everyone down, including myself.
|
||||
|
||||
I was attending South by Southwest in Austin, Texas, where I was [presenting my first Ignite Talk][2] on applying open source principles to government—a talk that was well received by the audience. I remember practicing, and practicing, and practicing more the day before and the morning of my talk. I got that high that comes after delivering a great talk. I had a book signing at the City of Raleigh's Economic Development booth during the event, which was another emotional boost. Life was good. Upon reflection, that's when I started noticing signs of my burnout.
|
||||
|
||||
I didn't have much of an appetite. I was tired all the time. I was sleeping in, and not because of jet lag. I was exercising but wasn't getting the endorphins I was used to. And I wasn't motivated to do the work that I normally love to do. I was very blah and meh about getting work done or hanging out with people I love. These are all signs of depression and burnout.
|
||||
|
||||
After the trip, I scheduled my annual physical and talked to my doctor about my situation, who recommended I see a psychologist. I sat on the couch and talked things out. I was diagnosed with severe anxiety, which was enough for me to know that I didn't want to know what true depression felt like.
|
||||
|
||||
I learned my lesson the hard way. I'd like to share my experience so that you can recognize the signs and avoid going down this path. And before we move on, I must say that it's perfectly fine to ask for help. Ask a trusted co-worker or friend for help or guidance. We're human, and we need to help each other through the ups and the downs.
|
||||
|
||||
### Three things to know about burnout
|
||||
|
||||
Work burnout is a form of depression where you are not motivated to do the things that are expected of you at your job. It's not the occasional slacking off or spring fever because the weather is nice. It's a buildup of emotional stress where you don't want to do what is asked of you at work. There are numerous factors that can lead to burnout.
|
||||
|
||||
#### Know the signs of burnout
|
||||
|
||||
Lesson number one about burnout is to know the signs. I mentioned some of the things I was experiencing, but there are many others. I remember one thing that was extremely abnormal for me (because I'm so social) is that I started to separate myself from my usual team activities and people.
|
||||
|
||||
* Hey Jason, want to grab lunch with us? Nope, I'm too busy.
|
||||
* Hey Jason, Matt's in town, want to join us for happy hour? No. I've got work to do.
|
||||
|
||||
|
||||
|
||||
This is totally unlike me. I would normally have said yes to both those opportunities. According to the [Mayo Clinic][3], here are a few things to ask yourself if you think you are experiencing burnout:
|
||||
|
||||
* Do you drag yourself to work?
|
||||
* Do you have trouble getting started with work?
|
||||
* Are you cynical or critical at work?
|
||||
* Have you become irritable or impatient with co-workers or customers?
|
||||
* Do you lack the energy to be productive?
|
||||
* Do you find it hard to concentrate?
|
||||
* Do you lack satisfaction from your achievements?
|
||||
* Do you feel disillusioned about your work?
|
||||
* Are you using food, drugs, or alcohol to feel better or to simply not feel?
|
||||
* Have your sleep habits changed?
|
||||
* Are you troubled by unexplained headaches, stomach or bowel problems, or other physical complaints?
|
||||
|
||||
|
||||
|
||||
You can check your own burnout risk at [BurnoutIndex.org][4], an anonymous online questionnaire created in response to the [high level of burnout][5] in the tech industry.
|
||||
|
||||
#### Prevent burnout
|
||||
|
||||
The second lesson is to identify ways [to prevent burnout][6]. First, take time away from your job and plan time to unplug and unwind. This means planning vacations, staycations, or other time away from work. It's sometimes hard to unplug like this with the pressures and obligations we put on ourselves.
|
||||
|
||||
There are three different levels of paid time off (PTO):
|
||||
|
||||
1. **Best way to unplug:** I'm totally cut-off, not logging in, not checking email.
|
||||
2. **Decent way to unplug:** I'm kind of checking in, but not as responsive as normal.
|
||||
3. **Meh way to unplug:** I'm available if you need me, I'll monitor email, but I'm away from normal office life.
|
||||
|
||||
|
||||
|
||||
Your situation will dictate which of these levels of time off will work for you. In my experience, you need at least two total check-outs a year. I typically have a blend of all three throughout the year, but since 2017, I have taken at least three week-long vacations each year to completely escape. It's working so far!
|
||||
|
||||
#### Manage stress
|
||||
|
||||
The third and final lesson is to manage stress effectively. My first go-to for stress management is exercise. I'm addicted to it. I work out pretty much every single day. And I like to mix it up: Cardio, weight lifting, swimming, running, cycling, surfing, and high-intensity interval training (HIIT) are staples in my exercise routine. I used to focus solely on running four to six half marathons a year, but I recently switched to triathlons. The multidisciplinary aspect of the activity has brought more joy and different challenges to my life.
|
||||
|
||||
Another way to reduce stress is to manage your time better. Time is our most precious resource. You've got to choose how you want to spend your time. Family, work, self, social? It's up to you. Find ways to work more efficiently, more effectively, and make sure that you put yourself first. It may sound selfish, but as I've learned from the airplane preflight safety videos, "you need to put your mask on first before helping others."
|
||||
|
||||
### Conclusion
|
||||
|
||||
Burnout can lead to fatigue, excessive stress, sadness, anger, irritability, insomnia, alcohol or substance misuse, heart disease, and other medical conditions—all things that are not good for humans or for your team at work. I hope you can use these tips to put yourself first, reduce stress, and prevent burnout.
|
||||
|
||||
* * *
|
||||
|
||||
_Jason Hibbets will present "[10 things I wish I knew before experiencing burnout][7]" at [SCaLE 18x][8], March 5–8, 2020, in Pasadena, Calif. This article is a preview for the talk and a way to share a bit of his experience._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/3/burnout
|
||||
|
||||
作者:[Jason Hibbets][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jhibbets
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bulb-light-energy-power-idea.png?itok=zTEEmTZB (Light bulb)
|
||||
[2]: https://schedule.sxsw.com/2017/events/PP96070
|
||||
[3]: https://www.mayoclinic.org/healthy-lifestyle/adult-health/in-depth/burnout/art-20046642
|
||||
[4]: https://burnoutindex.org/
|
||||
[5]: https://opensource.com/article/19/11/burnout-open-source-communities
|
||||
[6]: https://www.redhat.com/sysadmin/tips-avoiding-burnout
|
||||
[7]: https://www.socallinuxexpo.org/scale/18x/presentations/10-things-i-wish-i-knew-experiencing-burnout
|
||||
[8]: https://www.socallinuxexpo.org/scale/18x/
|
@ -1,229 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (mengxinayan)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to structure a multi-file C program: Part 2)
|
||||
[#]: via: (https://opensource.com/article/19/7/structure-multi-file-c-part-2)
|
||||
[#]: author: (Erik O'Shaughnessy https://opensource.com/users/jnyjny)
|
||||
|
||||
How to structure a multi-file C program: Part 2
|
||||
======
|
||||
Dive deeper into the structure of a C program composed of multiple files
|
||||
in the second part of this article.
|
||||
![4 manilla folders, yellow, green, purple, blue][1]
|
||||
|
||||
In [Part 1][2], I laid out the structure for a multi-file C program called [MeowMeow][3] that implements a toy [codec][4]. I also talked about the Unix philosophy of program design, laying out a number of empty files to start with a good structure from the very beginning. Lastly, I touched on what a Makefile is and what it can do for you. This article picks up where the other one left off and now I'll get to the actual implementation of our silly (but instructional) MeowMeow codec.
|
||||
|
||||
The structure of the **main.c** file for **meow**/**unmeow** should be familiar to anyone who's read my article "[How to write a good C main function][5]." It has the following general outline:
|
||||
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow, a stream encoder/decoder */
|
||||
|
||||
/* 00 system includes */
|
||||
/* 01 project includes */
|
||||
/* 02 externs */
|
||||
/* 03 defines */
|
||||
/* 04 typedefs */
|
||||
/* 05 globals (but don't)*/
|
||||
/* 06 ancillary function prototypes if any */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* 07 variable declarations */
|
||||
/* 08 check argv[0] to see how the program was invoked */
|
||||
/* 09 process the command line options from the user */
|
||||
/* 10 do the needful */
|
||||
}
|
||||
|
||||
/* 11 ancillary functions if any */
|
||||
```
|
||||
|
||||
### Including project header files
|
||||
|
||||
The second section, **/* 01 project includes /***, reads like this from the source:
|
||||
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow, a stream encoder/decoder */
|
||||
...
|
||||
/* 01 project includes */
|
||||
#include "main.h"
|
||||
#include "mmecode.h"
|
||||
#include "mmdecode.h"
|
||||
```
|
||||
|
||||
The **#include** directive is a C preprocessor command that causes the contents of the named file to be "included" at this point in the file. If the programmer uses double-quotes around the name of the header file, the compiler will look for that file in the current directory. If the file is enclosed in <>, it will look for the file in a set of predefined directories.
|
||||
|
||||
The file [**main.h**][6] contains the definitions and typedefs used in [**main.c**][7]. I like to collect these things here in case I want to use those definitions elsewhere in my program.
|
||||
|
||||
The files [**mmencode.h**][8] and [**mmdecode.h**][9] are nearly identical, so I'll break down **mmencode.h**.
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.h - MeowMeow, a stream encoder/decoder */
|
||||
|
||||
#ifndef _MMENCODE_H
|
||||
#define _MMENCODE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int mm_encode(FILE *src, FILE *dst);
|
||||
|
||||
#endif /* _MMENCODE_H */
|
||||
```
|
||||
|
||||
The **#ifdef, #define, #endif** construction is collectively known as a "guard." This keeps the C compiler from including this file more than once per file. The compiler will complain if it finds multiple definitions/prototypes/declarations, so the guard is a _must-have_ for header files.
|
||||
|
||||
Inside the guard, there are only two things: an **#include** directive and a function prototype declaration. I include **stdio.h** here to bring in the definition of **FILE** that is used in the function prototype. The function prototype can be included by other C files to establish that function in the file's namespace. You can think of each file as a separate _namespace_, which means variables and functions in one file are not usable by functions or variables in another file.
|
||||
|
||||
Writing header files is complex, and it is tough to manage in larger projects. Use guards.
|
||||
|
||||
### MeowMeow encoding, finally
|
||||
|
||||
The meat and potatoes of this program—encoding and decoding bytes into/out of **MeowMeow** strings—is actually the easy part of this project. All of our activities until now have been putting the scaffolding in place to support calling this function: parsing the command line, determining which operation to use, and opening the files that we'll operate on. Here is the encoding loop:
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.c - MeowMeow, a stream encoder/decoder */
|
||||
...
|
||||
while (![feof][10](src)) {
|
||||
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
|
||||
for(i=0; i<[strlen][12](buf); i++) {
|
||||
lo = (buf[i] & 0x000f);
|
||||
hi = (buf[i] & 0x00f0) >> 4;
|
||||
[fputs][13](tbl[hi], dst);
|
||||
[fputs][13](tbl[lo], dst);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In plain English, this loop reads in a chunk of the file while there are chunks left to read (**feof(3)** and **fgets(3)**). Then it splits each byte in the chunk into **hi** and **lo** nibbles. Remember, a nibble is half of a byte, or 4 bits. The real magic here is realizing that 4 bits can encode 16 values. I use **hi** and **lo** as indices into a 16-string lookup table, **tbl**, that contains the **MeowMeow** strings that encode each nibble. Those strings are written to the destination **FILE** stream using **fputs(3)**, then we move on to the next byte in the buffer.
|
||||
|
||||
The table is initialized with a macro defined in [**table.h**][14] for no particular reason except to demonstrate including another project local header file, and I like initialization macros. We will go further into why a future article.
|
||||
|
||||
### MeowMeow decoding
|
||||
|
||||
Alright, I'll admit it took me a couple of runs at this before I got it working. The decode loop is similar: read a buffer full of **MeowMeow** strings and reverse the encoding from strings to bytes.
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow, a stream decoder/decoder */
|
||||
...
|
||||
int mm_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
if (!src || !dst) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return stupid_decode(src, dst);
|
||||
}
|
||||
```
|
||||
|
||||
Not what you were expecting?
|
||||
|
||||
Here, I'm exposing the function **stupid_decode()** via the externally visible **mm_decode()** function. When I say "externally," I mean outside this file. Since **stupid_decode()** isn't in the header file, it isn't available to be called in other files.
|
||||
|
||||
Sometimes we do this when we want to publish a solid public interface, but we aren't quite done noodling around with functions to solve a problem. In my case, I've written an I/O-intensive function that reads 8 bytes at a time from the source stream to decode 1 byte to write to the destination stream. A better implementation would work on a buffer bigger than 8 bytes at a time. A _much_ better implementation would also buffer the output bytes to reduce the number of single-byte writes to the destination stream.
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow, a stream decoder/decoder */
|
||||
...
|
||||
int stupid_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
char buf[9];
|
||||
decoded_byte_t byte;
|
||||
int i;
|
||||
|
||||
while (![feof][10](src)) {
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
byte.field.f0 = [isupper][15](buf[0]);
|
||||
byte.field.f1 = [isupper][15](buf[1]);
|
||||
byte.field.f2 = [isupper][15](buf[2]);
|
||||
byte.field.f3 = [isupper][15](buf[3]);
|
||||
byte.field.f4 = [isupper][15](buf[4]);
|
||||
byte.field.f5 = [isupper][15](buf[5]);
|
||||
byte.field.f6 = [isupper][15](buf[6]);
|
||||
byte.field.f7 = [isupper][15](buf[7]);
|
||||
|
||||
[fputc][16](byte.value, dst);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Instead of using the bit-shifting technique I used in the encoder, I elected to create a custom data structure called **decoded_byte_t**.
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow, a stream decoder/decoder */
|
||||
...
|
||||
|
||||
typedef struct {
|
||||
unsigned char f7:1;
|
||||
unsigned char f6:1;
|
||||
unsigned char f5:1;
|
||||
unsigned char f4:1;
|
||||
unsigned char f3:1;
|
||||
unsigned char f2:1;
|
||||
unsigned char f1:1;
|
||||
unsigned char f0:1;
|
||||
} fields_t;
|
||||
|
||||
typedef union {
|
||||
fields_t field;
|
||||
unsigned char value;
|
||||
} decoded_byte_t;
|
||||
```
|
||||
|
||||
It's a little complex when viewed all at once, but hang tight. The **decoded_byte_t** is defined as a **union** of a **fields_t** and an **unsigned char**. The named members of a union can be thought of as aliases for the same region of memory. In this case, **value** and **field** refer to the same 8-bit region of memory. Setting **field.f0** to 1 would also set the least significant bit in **value**.
|
||||
|
||||
While **unsigned char** shouldn't be a mystery, the **typedef** for **fields_t** might look a little unfamiliar. Modern C compilers allow programmers to specify "bit fields" in a **struct**. The field type needs to be an unsigned integral type, and the member identifier is followed by a colon and an integer that specifies the length of the bit field.
|
||||
|
||||
This data structure makes it simple to access each bit in the byte by field name and then access the assembled value via the **value** field of the union. We depend on the compiler to generate the correct bit-shifting instructions to access the fields, which can save you a lot of heartburn when you are debugging.
|
||||
|
||||
Lastly, **stupid_decode()** is _stupid_ because it only reads 8 bytes at a time from the source **FILE** stream. Usually, we try to minimize the number of reads and writes to improve performance and reduce our cost of system calls. Remember that reading or writing a bigger chunk less often is much better than reading/writing a lot of smaller chunks more frequently.
|
||||
|
||||
### The wrap-up
|
||||
|
||||
Writing a multi-file program in C requires a little more planning on behalf of the programmer than just a single **main.c**. But just a little effort up front can save a lot of time and headache when you refactor as you add functionality.
|
||||
|
||||
To recap, I like to have a lot of files with a few short functions in them. I like to expose a small subset of the functions in those files via header files. I like to keep my constants in header files, both numeric and string constants. I _love_ Makefiles and use them instead of Bash scripts to automate all sorts of things. I like my **main()** function to handle command-line argument parsing and act as a scaffold for the primary functionality of the program.
|
||||
|
||||
I know I've only touched the surface of what's going on in this simple program, and I'm excited to learn what things were helpful to you and which topics need better explanations. Share your thoughts in the comments to let me know.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/7/structure-multi-file-c-part-2
|
||||
|
||||
作者:[Erik O'Shaughnessy][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[萌新阿岩](https://github.com/mengxinayan)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jnyjny
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/file_system.jpg?itok=pzCrX1Kc (4 manilla folders, yellow, green, purple, blue)
|
||||
[2]: https://opensource.com/article/19/7/how-structure-multi-file-c-program-part-1
|
||||
[3]: https://github.com/jnyjny/MeowMeow.git
|
||||
[4]: https://en.wikipedia.org/wiki/Codec
|
||||
[5]: https://opensource.com/article/19/5/how-write-good-c-main-function
|
||||
[6]: https://github.com/JnyJny/meowmeow/blob/master/main.h
|
||||
[7]: https://github.com/JnyJny/meowmeow/blob/master/main.c
|
||||
[8]: https://github.com/JnyJny/meowmeow/blob/master/mmencode.h
|
||||
[9]: https://github.com/JnyJny/meowmeow/blob/master/mmdecode.h
|
||||
[10]: http://www.opengroup.org/onlinepubs/009695399/functions/feof.html
|
||||
[11]: http://www.opengroup.org/onlinepubs/009695399/functions/fgets.html
|
||||
[12]: http://www.opengroup.org/onlinepubs/009695399/functions/strlen.html
|
||||
[13]: http://www.opengroup.org/onlinepubs/009695399/functions/fputs.html
|
||||
[14]: https://github.com/JnyJny/meowmeow/blob/master/table.h
|
||||
[15]: http://www.opengroup.org/onlinepubs/009695399/functions/isupper.html
|
||||
[16]: http://www.opengroup.org/onlinepubs/009695399/functions/fputc.html
|
@ -1,238 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (caiichenr)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Building a non-breaking breakpoint for Python debugging)
|
||||
[#]: via: (https://opensource.com/article/19/8/debug-python)
|
||||
[#]: author: (Liran Haimovitch https://opensource.com/users/liranhaimovitch)
|
||||
|
||||
Building a non-breaking breakpoint for Python debugging
|
||||
======
|
||||
Have you ever wondered how to speed up a debugger? Here are some lessons
|
||||
learned while building one for Python.
|
||||
![Real python in the graphic jungle][1]
|
||||
|
||||
This is the story of how our team at [Rookout][2] built non-breaking breakpoints for Python and some of the lessons we learned along the way. I'll be presenting all about the nuts and bolts of debugging in Python at [PyBay 2019][3] in San Francisco this month. Let's dig in.
|
||||
|
||||
### The heart of Python debugging: sys.set_trace
|
||||
|
||||
There are many Python debuggers out there. Some of the more popular include:
|
||||
|
||||
* **pdb**, part of the Python standard library
|
||||
* **PyDev**, the debugger behind the Eclipse and PyCharm IDEs
|
||||
* **ipdb**, the IPython debugger
|
||||
|
||||
|
||||
|
||||
Despite the range of choices, almost every Python debugger is based on just one function: **sys.set_trace**. And let me tell you, **[sys.settrace][4]** might just be the most complex function in the Python standard library.
|
||||
|
||||
![set_trace Python 2 docs page][5]
|
||||
|
||||
In simpler terms, **settrace** registers a trace function for the interpreter, which may be called in any of the following cases:
|
||||
|
||||
* Function call
|
||||
* Line execution
|
||||
* Function return
|
||||
* Exception raised
|
||||
|
||||
|
||||
|
||||
A simple trace function might look like this:
|
||||
|
||||
|
||||
```
|
||||
def simple_tracer(frame, event, arg):
|
||||
co = frame.f_code
|
||||
func_name = co.co_name
|
||||
line_no = frame.f_lineno
|
||||
print("{e} {f} {l}".format(
|
||||
e=event, f=func_name, l=line_no))
|
||||
return simple_tracer
|
||||
```
|
||||
|
||||
When looking at this function, the first things that come to mind are its arguments and return values. The trace function arguments are:
|
||||
|
||||
* **frame** object, which is the full state of the interpreter at the point of the function's execution
|
||||
* **event** string, which can be **call**, **line**, **return**, or **exception**
|
||||
* **arg** object, which is optional and depends on the event type
|
||||
|
||||
|
||||
|
||||
The trace function returns itself because the interpreter keeps track of two kinds of trace functions:
|
||||
|
||||
* **Global trace function (per thread):** This trace function is set for the current thread by **sys.settrace** and is invoked whenever a new **frame** is created by the interpreter (essentially on every function call). While there's no documented way to set the trace function for a different thread, you can call **threading.settrace** to set the trace function for all newly created **threading** module threads.
|
||||
* **Local trace function (per frame):** This trace function is set by the interpreter to the value returned by the global trace function upon frame creation. There's no documented way to set the local trace function once the frame has been created.
|
||||
|
||||
|
||||
|
||||
This mechanism is designed to allow the debugger to have more granular control over which frames are traced to reduce performance impact.
|
||||
|
||||
### Building our debugger in three easy steps (or so we thought)
|
||||
|
||||
With all that background, writing your own debugger using a custom trace function looks like a daunting task. Luckily, **pdb**, the standard Python debugger, is built on top of **Bdb**, a base class for building debuggers.
|
||||
|
||||
A naive breakpoints debugger based on **Bdb** might look like this:
|
||||
|
||||
|
||||
```
|
||||
import bdb
|
||||
import inspect
|
||||
|
||||
class Debugger(bdb.Bdb):
|
||||
def __init__(self):
|
||||
Bdb.__init__(self)
|
||||
self.breakpoints = dict()
|
||||
self.set_trace()
|
||||
|
||||
def set_breakpoint(self, filename, lineno, method):
|
||||
self.set_break(filename, lineno)
|
||||
try :
|
||||
self.breakpoints[(filename, lineno)].add(method)
|
||||
except KeyError:
|
||||
self.breakpoints[(filename, lineno)] = [method]
|
||||
|
||||
def user_line(self, frame):
|
||||
if not self.break_here(frame):
|
||||
return
|
||||
|
||||
# Get filename and lineno from frame
|
||||
(filename, lineno, _, _, _) = inspect.getframeinfo(frame)
|
||||
|
||||
methods = self.breakpoints[(filename, lineno)]
|
||||
for method in methods:
|
||||
method(frame)
|
||||
```
|
||||
|
||||
All this does is:
|
||||
|
||||
1. Inherits from **Bdb** and write a simple constructor initializing the base class and tracing.
|
||||
2. Adds a **set_breakpoint** method that uses **Bdb** to set the breakpoint and keeps track of our breakpoints.
|
||||
3. Overrides the **user_line** method that is called by **Bdb** on certain user lines. The function makes sure it is being called for a breakpoint, gets the source location, and invokes the registered breakpoints
|
||||
|
||||
|
||||
|
||||
### How well did the simple Bdb debugger work?
|
||||
|
||||
Rookout is about bringing a debugger-like user experience to production-grade performance and use cases. So, how well did our naive breakpoint debugger perform?
|
||||
|
||||
To test it and measure the global performance overhead, we wrote two simple test methods and executed each of them 16 million times under multiple scenarios. Keep in mind that no breakpoint was executed in any of the cases.
|
||||
|
||||
|
||||
```
|
||||
def empty_method():
|
||||
pass
|
||||
|
||||
def simple_method():
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
d = 4
|
||||
e = 5
|
||||
f = 6
|
||||
g = 7
|
||||
h = 8
|
||||
i = 9
|
||||
j = 10
|
||||
```
|
||||
|
||||
Using the debugger takes a shocking amount of time to complete. The bad results make it clear that our naive **Bdb** debugger is not yet production-ready.
|
||||
|
||||
![First Bdb debugger results][6]
|
||||
|
||||
### Optimizing the debugger
|
||||
|
||||
There are three main ways to reduce debugger overhead:
|
||||
|
||||
1. **Limit local tracing as much as possible:** Local tracing is very costly compared to global tracing due to the much larger number of events per line of code.
|
||||
2. **Optimize "call" events and return control to the interpreter faster:** The main work in **call** events is deciding whether or not to trace.
|
||||
3. **Optimize "line" events and return control to the interpreter faster:** The main work in **line** events is deciding whether or not we hit a breakpoint.
|
||||
|
||||
|
||||
|
||||
So we forked **Bdb**, reduced the feature set, simplified the code, optimized for hot code paths, and got impressive results. However, we were still not satisfied. So, we took another stab at it, migrated and optimized our code to **.pyx**, and compiled it using [Cython][7]. The final results (as you can see below) were still not good enough. So, we ended up diving into CPython's source code and realizing we could not make tracing fast enough for production use.
|
||||
|
||||
![Second Bdb debugger results][8]
|
||||
|
||||
### Rejecting Bdb in favor of bytecode manipulation
|
||||
|
||||
After our initial disappointment from the trial-and-error cycles of standard debugging methods, we decided to look into a less obvious option: bytecode manipulation.
|
||||
|
||||
The Python interpreter works in two main stages:
|
||||
|
||||
1. **Compiling Python source code into Python bytecode:** This unreadable (for humans) format is optimized for efficient execution and is often cached in those **.pyc** files we have all come to love.
|
||||
2. **Iterating through the bytecode in the _interpreter loop_:** This executes one instruction at a time.
|
||||
|
||||
|
||||
|
||||
This is the pattern we chose: use **bytecode manipulation** to set **non-breaking breakpoints** with no global overhead. This is done by finding the bytecode in memory that represents the source line we are interested in and inserting a function call just before the relevant instruction. This way, the interpreter does not have to do any extra work to support our breakpoints.
|
||||
|
||||
This approach is not magic. Here's a quick example.
|
||||
|
||||
We start with a very simple function:
|
||||
|
||||
|
||||
```
|
||||
def multiply(a, b):
|
||||
result = a * b
|
||||
return result
|
||||
```
|
||||
|
||||
In documentation hidden in the **[inspect][9]** module (which has several useful utilities), we learn we can get the function's bytecode by accessing **multiply.func_code.co_code**:
|
||||
|
||||
|
||||
```
|
||||
`'|\x00\x00|\x01\x00\x14}\x02\x00|\x02\x00S'`
|
||||
```
|
||||
|
||||
This unreadable string can be improved using the **[dis][10]** module in the Python standard library. By calling **dis.dis(multiply.func_code.co_code)**, we get:
|
||||
|
||||
|
||||
```
|
||||
4 0 LOAD_FAST 0 (a)
|
||||
3 LOAD_FAST 1 (b)
|
||||
6 BINARY_MULTIPLY
|
||||
7 STORE_FAST 2 (result)
|
||||
|
||||
5 10 LOAD_FAST 2 (result)
|
||||
13 RETURN_VALUE
|
||||
```
|
||||
|
||||
This gets us closer to understanding what happens behind the scenes of debugging but not to a straightforward solution. Unfortunately, Python does not offer a method for changing a function's bytecode from within the interpreter. You can overwrite the function object, but that's not good enough for the majority of real-world debugging scenarios. You have to go about it in a roundabout way using a native extension.
|
||||
|
||||
### Conclusion
|
||||
|
||||
When building a new tool, you invariably end up learning a lot about how stuff works. It also makes you think out of the box and keep your mind open to unexpected solutions.
|
||||
|
||||
Working on non-breaking breakpoints for Rookout has taught me a lot about compilers, debuggers, server frameworks, concurrency models, and much much more. If you are interested in learning more about bytecode manipulation, Google's open source **[cloud-debug-python][11]** has tools for editing bytecode.
|
||||
|
||||
* * *
|
||||
|
||||
_Liran Haimovitch will present "[Understanding Python’s Debugging Internals][12]" at [PyBay][3], which will be held August 17-18 in San Francisco. Use code [OpenSource35][13] for a discount when you purchase your ticket to let them know you found out about the event from our community._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/8/debug-python
|
||||
|
||||
作者:[Liran Haimovitch][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/liranhaimovitch
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python_jungle_lead.jpeg?itok=pFKKEvT- (Real python in the graphic jungle)
|
||||
[2]: https://rookout.com/
|
||||
[3]: https://pybay.com/
|
||||
[4]: https://docs.python.org/3/library/sys.html#sys.settrace
|
||||
[5]: https://opensource.com/sites/default/files/uploads/python2docs.png (set_trace Python 2 docs page)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/debuggerresults1.png (First Bdb debugger results)
|
||||
[7]: https://cython.org/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/debuggerresults2.png (Second Bdb debugger results)
|
||||
[9]: https://docs.python.org/2/library/inspect.html
|
||||
[10]: https://docs.python.org/2/library/dis.html
|
||||
[11]: https://github.com/GoogleCloudPlatform/cloud-debug-python
|
||||
[12]: https://pybay.com/speaker/liran-haimovitch/
|
||||
[13]: https://ti.to/sf-python/pybay2019/discount/OpenSource35
|
@ -1,143 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (HankChow)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Session: An Open Source Private Messenger That Doesn’t Need Your Phone Number)
|
||||
[#]: via: (https://itsfoss.com/session-messenger/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
Session: An Open Source Private Messenger That Doesn’t Need Your Phone Number
|
||||
======
|
||||
|
||||
_**Brief: Our open source software highlight of the week is Session. It is a fork of another increasingly popular private messenger Signal. Session doesn’t even need your phone number to operate.**_
|
||||
|
||||
### Session: A private messenger in true sense
|
||||
|
||||
![][1]
|
||||
|
||||
Privacy concerned people are always in the search of an ultimate service that lets you communicate securely while respecting our privacy across multiple platforms.
|
||||
|
||||
Recently, I came across an interesting open-source messaging app “[Session][2]” by [Loki Foundation][3], which is technically a fork of another [open source encrypted messenger Signal][4].
|
||||
|
||||
In this article, I’ll be sharing my experience with the Session app while highlighting the features it offers.
|
||||
|
||||
Session is fairly new to the scene – I’ve mentioned some of the bugs that I encountered at the bottom of the article.
|
||||
|
||||
### Features of Session Messenger
|
||||
|
||||
I’ll highlight the key features of Session that will help you decide if it’s good enough for you to try.
|
||||
|
||||
#### Session does not require a phone number
|
||||
|
||||
![][5]
|
||||
|
||||
For privacy-enthusiasts, registering the phone number with Signal or other such applications is a potential risk.
|
||||
|
||||
But, with Session, you do not need a phone number, simply click on “**Create Account**” after you install it on your desktop or phone and it will simply generate a random (unique) **Session ID**.
|
||||
|
||||
It’ll look something like this: **05652245af9a8bfee4f5a8138fd5c……..**
|
||||
|
||||
So, you just have to share your Session ID with the contact you want to add. Or, you can also opt to get the **QR Code** after account creation which you can share with your friends to add you back.
|
||||
|
||||
#### Session uses blockchain (and other crypto tech)
|
||||
|
||||
![Session ID][6]
|
||||
|
||||
For the users who’re aware of what a [blockchain][7] is – they’ve been waiting for real-world applications that an average user can utilize. Session is one such example that utilizes blockchain at its core and you don’t need to know it’s there.
|
||||
|
||||
If you’re curious about how it works, you can take a look at their [official blog post][8] explaining it.
|
||||
|
||||
#### Cross-Platform Support
|
||||
|
||||
![][9]
|
||||
|
||||
For something strictly privacy-focused, you’d also want it to be available across multiple platforms.
|
||||
|
||||
Of course, primarily, I’d focus on the Linux and Android support but it also supports Windows/Mac/iOS. So, you can easily sync between multiple devices cross-platform.
|
||||
|
||||
#### Includes Essential Privacy Options
|
||||
|
||||
![][10]
|
||||
|
||||
Undoubtedly, it offers some essential privacy-focused features that will help make the experience more secure.
|
||||
|
||||
For starters, you have the following options:
|
||||
|
||||
* **Message TTL**: This lets you control how long the message exists before the recipient sees the message.
|
||||
* **Read Receipts**: Let others know that you’ve seen the message or if your message has been read.
|
||||
|
||||
|
||||
|
||||
#### Session uses a decentralized network and protects your metadata
|
||||
|
||||
Even though Session isn’t a peer-to-peer technology, it does not have a central server for the network.
|
||||
|
||||
It takes a decentralized approach to how the messages are transmitted (or routed). If you’ve no idea what I’m talking about, you can follow Session’s official blog post to know the [difference between centralization and decentralization][11] and explore how it potentially works.
|
||||
|
||||
And, this approach of network helps them to protect the metadata (the information associated with a message like IP address).
|
||||
|
||||
#### Other Features
|
||||
|
||||
Not just limited to the latest/greatest privacy-friendly features, but it also supports group chats, voice messages, and also allows you to send attachments.
|
||||
|
||||
### Installing Session on Linux
|
||||
|
||||
If you head to the [official download page][12], you will be able to download an .**AppImage** file. In case you have no clue how it works, you should take a look at our article on [how to use AppImage][13].
|
||||
|
||||
In either case, you can also head to their [GitHub releases page][14] and grab the **.deb** file.
|
||||
|
||||
[Download Session][12]
|
||||
|
||||
### My Experience On Using Session App
|
||||
|
||||
I’ve managed to try it on multiple platforms. For the desktop, I utilized the .AppImage file on **Pop!_OS 19.10** to run Session.
|
||||
|
||||
Overall, the user experience was impressive and had no UI glitches.
|
||||
|
||||
It’s also easy to recover your account once you’ve backed up your secret code (which is known as **seed**) from the settings.
|
||||
|
||||
![][15]
|
||||
|
||||
But, I also noticed a couple of issues- which can be fixed/improved:
|
||||
|
||||
* Delay in accepting a friend request
|
||||
* The way of linking devices is not intuitive
|
||||
* Sometimes when you reply from two separate devices (using the same ID), the receiver gets two different conversations.
|
||||
|
||||
|
||||
|
||||
**Conclusion**
|
||||
|
||||
Of course, nothing’s ever perfect. For now, I’m thinking of keeping it installed and considering Session’s features, it is definitely something a privacy-focused user should try.
|
||||
|
||||
What do you think about it? Feel free to let me know your thoughts in the comments below.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/session-messenger/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-app.jpg?ssl=1
|
||||
[2]: https://getsession.org/
|
||||
[3]: https://loki.foundation/
|
||||
[4]: https://itsfoss.com/signal-messaging-app/
|
||||
[5]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-create.jpg?ssl=1
|
||||
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/03/session-application-id.jpg?ssl=1
|
||||
[7]: https://en.wikipedia.org/wiki/Blockchain
|
||||
[8]: https://getsession.org/how-session-protects-your-anonymity-with-blockchain-and-crypto/
|
||||
[9]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-cross-platform.jpg?ssl=1
|
||||
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-settings.jpg?fit=800%2C512&ssl=1
|
||||
[11]: https://getsession.org/centralisation-vs-decentralisation-in-private-messaging/
|
||||
[12]: https://getsession.org/download/
|
||||
[13]: https://itsfoss.com/use-appimage-linux/
|
||||
[14]: https://github.com/loki-project/session-desktop/releases
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-seed.jpg?ssl=1
|
@ -0,0 +1,148 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Communicating with other users on the Linux command line)
|
||||
[#]: via: (https://www.networkworld.com/article/3530343/communicating-with-other-users-on-the-linux-command-line.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
Communicating with other users on the Linux command line
|
||||
======
|
||||
|
||||
Thinkstock / Linux
|
||||
|
||||
Sending messages to other users on the Linux command line can be very easy, but there are a number of commands that you might want to consider. In this post, we’ll look at four commands and see how each of them works.
|
||||
|
||||
### wall
|
||||
|
||||
The **wall** command (as in "write all") allows you to send a message to all users who are currently logged into the system. This implies that the system is likely a server and that users are working on the command line. While the wall command is generally used by sysadmins to send out notices to users to let send out information (e.g., that the server is going down for maintenance), it can be used by any user.
|
||||
|
||||
A sysadmin might send out a message like this:
|
||||
|
||||
```
|
||||
$ wall The system will be going down in 15 minutes to address a serious problem
|
||||
```
|
||||
|
||||
Everyone logged into the system will see something like this:
|
||||
|
||||
```
|
||||
Broadcast message from admin@dragonfly (pts/0) (Thu Mar 5 08:56:42 2020):
|
||||
|
||||
The system is going down in 15 minutes to address a serious problem
|
||||
```
|
||||
|
||||
If you want to use single quote marks in your message, enclose the message in double quote marks like this:
|
||||
|
||||
```
|
||||
$ wall “Don’t forget to save your work before logging off”
|
||||
```
|
||||
|
||||
The outside quote marks will not show up in the transmitted message, but, without them, the command sits and waits for a closing single quote.
|
||||
|
||||
### mesg
|
||||
|
||||
If, for some reason, you don’t want to accept messages from another user, you can stop them from arriving with the **mesg** command. This command can be used with a “n” argument to refuse mail from the user or a “y” argument to allow the messages to arrive.
|
||||
|
||||
[][1]
|
||||
|
||||
```
|
||||
$ mesg n doug
|
||||
$ mesg y doug
|
||||
```
|
||||
|
||||
The blocked user will not be notified that their messages have been blocked. You can also block or allow all messages with a **mesg** command like one of these:
|
||||
|
||||
```
|
||||
$ mesg y
|
||||
$ mesg n
|
||||
```
|
||||
|
||||
### write
|
||||
|
||||
Another command for sending text without reverting to email is **write**. This command can be used to communicate with a specific user.
|
||||
|
||||
```
|
||||
$ write nemo
|
||||
Are you still at your desk?
|
||||
I need to talk with you right away.
|
||||
^C
|
||||
```
|
||||
|
||||
Enter your text and use **^C** to exit when you’re done. The command allows you to send text, but doesn’t start a two-way conversation. It just sends the text. If the user is logged in on more than one terminal, you can specify which terminal you want to send the message to or you can rely on the system to choose the one with the shortest idle time.
|
||||
|
||||
```
|
||||
$ write nemo#1
|
||||
```
|
||||
|
||||
If the user you are trying to write to has messages blocked, you should see something like this:
|
||||
|
||||
```
|
||||
$ write nemo
|
||||
write: nemo has messages disabled
|
||||
```
|
||||
|
||||
### talk/ytalk
|
||||
|
||||
The **talk** or **ytalk** command gives you a chance to have an interactive chat with one or more other users. The command will bring up a double-pane (top and bottom) window. Each individual will type into the top portion of the display on their screen and see the responses in the bottom section(s). The respondents can respond to a talk request by typing "talk" followed by the username of the person addressing them.
|
||||
|
||||
```
|
||||
Message from Talk_Daemon@dragonfly at 10:10 ...
|
||||
talk: connection requested by dory@127.0.0.1.
|
||||
talk: respond with: talk dory@127.0.0.1
|
||||
|
||||
$ talk dory
|
||||
```
|
||||
|
||||
The window can involve more than two participants if **ytalk** is used. As you can see in the example below (the result of the "talk dory" command shown above), talk is often ytalk.
|
||||
|
||||
```
|
||||
----------------------------= YTalk version 3.3.0 =--------------------------
|
||||
Is the report ready?
|
||||
|
||||
-------------------------------= nemo@dragonfly =----------------------------
|
||||
Just finished it
|
||||
```
|
||||
|
||||
As explained above, on the other side of the conversation, the talk session window panes are reversed:
|
||||
|
||||
```
|
||||
----------------------------= YTalk version 3.3.0 =--------------------------
|
||||
Just finished it
|
||||
|
||||
-------------------------------= dory@dragonfly =----------------------------
|
||||
Is the report ready?
|
||||
```
|
||||
|
||||
Again, use **^C** to exit.
|
||||
|
||||
To talk with someone on another system, you just need to add a **-h** option and the hostname or IP address with a command like this:
|
||||
|
||||
```
|
||||
$ talk -h 192.168.0.11 nemo
|
||||
```
|
||||
|
||||
### Wrap-Up
|
||||
|
||||
There are a number of basic commands for sending messages to other logged-in users on Linux systems, and they can be especially useful when you need to send out a quick message to all of the users, prefer a quick exchange to a phone call or want to easily involve more than two people in a quick messaging session.
|
||||
|
||||
Some commands, like **wall**, allow a message to be broadcast, but are not interactive. Others, like **talk**, allow both lengthy and multi-user chats, avoiding the need to set up a conference call when a fairly quick exchange of information is all that's required.
|
||||
|
||||
Join the Network World communities on [Facebook][2] and [LinkedIn][3] to comment on topics that are top of mind.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3530343/communicating-with-other-users-on-the-linux-command-line.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.networkworld.com/article/3440100/take-the-intelligent-route-with-consumption-based-storage.html?utm_source=IDG&utm_medium=promotions&utm_campaign=HPE21620&utm_content=sidebar ( Take the Intelligent Route with Consumption-Based Storage)
|
||||
[2]: https://www.facebook.com/NetworkWorld/
|
||||
[3]: https://www.linkedin.com/company/network-world
|
@ -0,0 +1,226 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (mengxinayan)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to structure a multi-file C program: Part 2)
|
||||
[#]: via: (https://opensource.com/article/19/7/structure-multi-file-c-part-2)
|
||||
[#]: author: (Erik O'Shaughnessy https://opensource.com/users/jnyjny)
|
||||
|
||||
如何组织构建多文件 C 语言程序(二)
|
||||
======
|
||||
我将在本系列的第二篇中深入研究由多个文件组成的C程序的结构。
|
||||
![4 个 manilla 文件,黄色,绿色,紫色,蓝色][1]
|
||||
|
||||
在 [(第一篇)][2] 中,我设计了一个名为 [MeowMeow][3] 的多文件 C 程序,该程序实现了一个玩具——[codec][4]。我提到了程序设计中的 Unix 哲学,即在一开始创建多个空文件,并建立一个好的结构。最后,我创建了一个 Makefile 文件夹并阐述了它的作用。在本文中将另一个方向展开:现在我将介绍简单但具有指导性的 MeowMeow 编/解码器的实现。
|
||||
|
||||
当读过我的 "[如何写一个好的 C 语言 main 函数][5]." 后,你便会知道 `main.c` 文件中 `meow` 和 `unmeow` 的结构,其主体结构如下:
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow 流编码器和解码器 */
|
||||
|
||||
/* 00 system includes */
|
||||
/* 01 project includes */
|
||||
/* 02 externs */
|
||||
/* 03 defines */
|
||||
/* 04 typedefs */
|
||||
/* 05 globals (but don't)*/
|
||||
/* 06 ancillary function prototypes if any */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* 07 variable declarations */
|
||||
/* 08 check argv[0] to see how the program was invoked */
|
||||
/* 09 process the command line options from the user */
|
||||
/* 10 do the needful */
|
||||
}
|
||||
|
||||
/* 11 ancillary functions if any */
|
||||
```
|
||||
|
||||
### 包含项目头文件
|
||||
|
||||
位于第二部分中的 `/* 01 project includes */` 的源代码如下:
|
||||
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow 流编码器和解码器 */
|
||||
...
|
||||
/* 01 project includes */
|
||||
#include "main.h"
|
||||
#include "mmecode.h"
|
||||
#include "mmdecode.h"
|
||||
```
|
||||
|
||||
`#include` 是 C 语言的预处理命令,它会将其后面的文件内容拷贝到当前文件中。如果程序员在头文件名称周围使用双引号,编译器将会在当前目录寻找该文件。如果文件被尖括号包围,编译器将在一组预定义的目录中查找该文件。
|
||||
|
||||
[main.h][6] 文件中包含了 [main.c][7] 文件中用到的定义和别名。我喜欢在头文件里尽可能多的声明,以便我想在我的程序的其他位置使用这些定义。
|
||||
|
||||
头文件 [mmencode.h][8] 和 [mmdecode.h][9] 几乎相同,因此我以 `mmencode.h` 为例来分析。
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.h - MeowMeow 流编码器和解码器 */
|
||||
|
||||
#ifndef _MMENCODE_H
|
||||
#define _MMENCODE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int mm_encode(FILE *src, FILE *dst);
|
||||
|
||||
#endif /* _MMENCODE_H */
|
||||
```
|
||||
|
||||
`#ifdef`,`#define`,`#endif` 指令统称为 “防护” 指令。其可以防止 C 编译器在一个文件中多次包含同一文件。如果编译器在一个文件中发现多个定义/原型/声明,它将会产生警告。因此这些防护措施是必要的。
|
||||
|
||||
在防护内部,它只做两件事:`#include` 指令和函数原型声明。我将包含 `stdio.h` 头文件,以便于能在函数原型中使用 `FILE` 流。函数原型也可以被包含在其他 C 文件中,以便于在文件的命名空间中创建它。你可以将每个文件视为一个命名空间,其中的变量和函数不能被另一个文件中的函数或者变量使用。
|
||||
|
||||
编写头文件很复杂,并且在大型项目中很难管理它。不要忘记使用防护。
|
||||
|
||||
### MeowMeow 编码的实现
|
||||
|
||||
该程序的功能是按照字节进行 `MeowMeow` 字符串的编解码,事实上这是该项目中最简单的部分。截止目前我所做的工作便是支持允许在适当的位置调用此函数:解析命令行,确定要使用的操作,并打开将要操作的文件。下面的循环是编码的过程:
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.c - MeowMeow 流编码器 */
|
||||
...
|
||||
while (![feof][10](src)) {
|
||||
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
|
||||
for(i=0; i<[strlen][12](buf); i++) {
|
||||
lo = (buf[i] & 0x000f);
|
||||
hi = (buf[i] & 0x00f0) >> 4;
|
||||
[fputs][13](tbl[hi], dst);
|
||||
[fputs][13](tbl[lo], dst);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
简单的说,上面代码循环读取文件的一部分,剩下的内容通过 `feof(3)` 函数和 `fgets(3)` 函数读取。然后将读入的内容的每个字节分成 `hi` 和 `lo` 半个字节。半个字节是 4 个比特。这里的奥妙之处在于可以用 4 个比特来编码16个值。我将字符串 `hi` 和 `lo` 用作 16 字符串查找表 `tbl` 的索引,表中包含了对每半个字节编码后的 `MeowMeow` 字符串。这些字符串使用 `fputs(3)` 函数写入目标 `FILE` 流,然后移动到缓存区的下一个字节。
|
||||
|
||||
该表使用 [table.h][14] 中的宏定义进行初始化,在没有特殊原因(比如:要展示包含了另一个项目的本地头文件)时,我喜欢使用宏来进行初始化。我将在未来的文章中进一步探讨原因。
|
||||
|
||||
### MeowMeow 解码的实现
|
||||
|
||||
我承认在开始工作前花了一些时间。解码的循环与编码类似:读取 `MeowMeow` 字符串到缓冲区,将编码从字符串转换为字节
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow 流解码器 */
|
||||
...
|
||||
int mm_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
if (!src || !dst) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return stupid_decode(src, dst);
|
||||
}
|
||||
```
|
||||
|
||||
这不是所期望的吗?
|
||||
|
||||
在这里,我通过外部公开的 `mm_decode()` 函数公开了 `stupid_decode()` 函数细节。我上面所说的“外部”是指在这个文件之外。因为 `stupid_decode()` 函数不在头文件中,因此无法在其他文件中调用它。
|
||||
|
||||
当我们想发布一个可靠的公共接口时,有时候会这样做,但是我们还没有完全使用函数解决问题。在本例中,我编写了一个 I/O 密集型函数,该函数每次从源中读取 8 个字节,然后解码获得 1 个字节写入目标流中。较好的实现是一次处理多于 8 个字节的缓冲区。更好的实现还可以通过缓冲区输出字节,进而减少目标流中单字节的写入次数。
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow 流解码器 */
|
||||
...
|
||||
int stupid_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
char buf[9];
|
||||
decoded_byte_t byte;
|
||||
int i;
|
||||
|
||||
while (![feof][10](src)) {
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
byte.field.f0 = [isupper][15](buf[0]);
|
||||
byte.field.f1 = [isupper][15](buf[1]);
|
||||
byte.field.f2 = [isupper][15](buf[2]);
|
||||
byte.field.f3 = [isupper][15](buf[3]);
|
||||
byte.field.f4 = [isupper][15](buf[4]);
|
||||
byte.field.f5 = [isupper][15](buf[5]);
|
||||
byte.field.f6 = [isupper][15](buf[6]);
|
||||
byte.field.f7 = [isupper][15](buf[7]);
|
||||
|
||||
[fputc][16](byte.value, dst);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
我并没有使用编码器中使用的位移方法,而是创建了一个名为 `decoded_byte_t` 的自定义数据结构。
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow 流解码器 */
|
||||
...
|
||||
|
||||
typedef struct {
|
||||
unsigned char f7:1;
|
||||
unsigned char f6:1;
|
||||
unsigned char f5:1;
|
||||
unsigned char f4:1;
|
||||
unsigned char f3:1;
|
||||
unsigned char f2:1;
|
||||
unsigned char f1:1;
|
||||
unsigned char f0:1;
|
||||
} fields_t;
|
||||
|
||||
typedef union {
|
||||
fields_t field;
|
||||
unsigned char value;
|
||||
} decoded_byte_t;
|
||||
```
|
||||
|
||||
初次看到代码时可能会感到有点儿复杂,但不要放弃。`decoded_byte_t` 被定义为 `fields_t` 和 `unsigned char` 的 **联合体** 。可以将联合中的命名成员看作同一内存区域的别名。在这种情况下,`value` 和 `field` 指向相同的 8 比特内存区域。将 `field.f0` 设置为 1 也将设置 `value` 中的最低有效位。
|
||||
|
||||
虽然 `unsigned char` 并不神秘,但是对 `fields_t` 的 别名(`typedef`) 也许看起来有些陌生。现代 C 编译器允许程序员在结构体中指定单个 bit 的值。`field` 成员是一个无符号整数类型,可以在成员标识符后紧跟一个冒号和一个整数,该整数指定了比特字段的长度。
|
||||
|
||||
这种数据结构使得按 `field` 名称访问每个比特变得简单。我们依赖编译器生成正确的移位指令来访问 `field`,这可以在调试时为你节省不少时间。
|
||||
|
||||
最后,因为`stupid_decode()` 函数一次仅从源 `FILE` 流中读取 8 个字节,所以它效率并不高。通常我们尝试最小化读写次数,以提高性能和降低调用系统调用的开销。请记住:少次数的读取/写入大的块比多次数的读取/写入小的块好得多。
|
||||
|
||||
### 总结
|
||||
|
||||
用 C 语言编写一个多文件程序需要程序员做更多计划,而不仅仅是一个 `main.c`。但是当你添加功能或者重构时,只需要多花费一点儿努力便可以节省大量时间以及避免让你头痛的问题。
|
||||
|
||||
回顾一下,我更喜欢这样做:多个文件,每个文件仅有简单功能;通过头文件公开那些文件中的小部分功能;把数字常量和字符串常量保存在头文件中;使用 `Makefile` 而不是 Bash 脚本来自动化处理事务;使用 `main()` 函数来处理和解析命令行参数并作为程序主要功能的框架。
|
||||
|
||||
我知道我只是涉及了这个简单程序中发生的事情,并且我很高兴知道哪些事情对您有所帮助以及哪些主题需要详细的解释。在评论中分享您的想法,让我知道。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/7/structure-multi-file-c-part-2
|
||||
|
||||
作者:[Erik O'Shaughnessy][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[萌新阿岩](https://github.com/mengxinayan)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jnyjny
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/file_system.jpg?itok=pzCrX1Kc (4 manilla folders, yellow, green, purple, blue)
|
||||
[2]: https://opensource.com/article/19/7/how-structure-multi-file-c-program-part-1
|
||||
[3]: https://github.com/jnyjny/MeowMeow.git
|
||||
[4]: https://en.wikipedia.org/wiki/Codec
|
||||
[5]: https://opensource.com/article/19/5/how-write-good-c-main-function
|
||||
[6]: https://github.com/JnyJny/meowmeow/blob/master/main.h
|
||||
[7]: https://github.com/JnyJny/meowmeow/blob/master/main.c
|
||||
[8]: https://github.com/JnyJny/meowmeow/blob/master/mmencode.h
|
||||
[9]: https://github.com/JnyJny/meowmeow/blob/master/mmdecode.h
|
||||
[10]: http://www.opengroup.org/onlinepubs/009695399/functions/feof.html
|
||||
[11]: http://www.opengroup.org/onlinepubs/009695399/functions/fgets.html
|
||||
[12]: http://www.opengroup.org/onlinepubs/009695399/functions/strlen.html
|
||||
[13]: http://www.opengroup.org/onlinepubs/009695399/functions/fputs.html
|
||||
[14]: https://github.com/JnyJny/meowmeow/blob/master/table.h
|
||||
[15]: http://www.opengroup.org/onlinepubs/009695399/functions/isupper.html
|
||||
[16]: http://www.opengroup.org/onlinepubs/009695399/functions/fputc.html
|
@ -0,0 +1,237 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (caiichenr)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Building a non-breaking breakpoint for Python debugging)
|
||||
[#]: via: (https://opensource.com/article/19/8/debug-python)
|
||||
[#]: author: (Liran Haimovitch https://opensource.com/users/liranhaimovitch)
|
||||
|
||||
在 Python 调试过程中设置不中断的断点
|
||||
======
|
||||
你对如何让调试器变得更快产生过兴趣吗?本文将分享我们在为 Python 构建调试器时得到的一些经验。
|
||||
![Real python in the graphic jungle][1]
|
||||
|
||||
整段故事讲的是我们在 [Rookout][2] 公司的团队为 Python 调试器开发不中断断点的经历,以及开发过程中得到的经验。我将在本月于旧金山举办的 [PyBay 2019][3] 上介绍有关 Python 调试过程的更多细节,但现在就让我们立刻开始这段故事。
|
||||
|
||||
### Python 调试器的心脏:sys.set_trace
|
||||
|
||||
在诸多可选的 Python 调试器中,使用最广泛的三个是:
|
||||
|
||||
* **pdb**,它是 Python 标准库的一部分
|
||||
* **PyDev**,它是内嵌在 Eclipse 和 Pycharm 等 IDE 中的调试器
|
||||
* **ipdb**,它是IPython的调试器
|
||||
|
||||
|
||||
|
||||
Python 调试器的选择虽多,但它们几乎都基于同一个函数:**sys.set_trace**。 值得一提的是, **[sys.settrace][4]** 可能也是 Python 标准库中最复杂的函数。
|
||||
|
||||
![set_trace Python 2 docs page][5]
|
||||
|
||||
简单来讲,**settrace** 的作用是为解释器注册一个跟踪函数,它在下列四种情形发生时被调用:
|
||||
|
||||
* 函数调用 (Function call)
|
||||
* 语句执行 (Line execution)
|
||||
* 函数返回 (Function return)
|
||||
* 异常抛出 (Exception raised)
|
||||
|
||||
|
||||
|
||||
一个简单的跟踪函数看上去大概是这样:
|
||||
|
||||
|
||||
```
|
||||
def simple_tracer(frame, event, arg):
|
||||
co = frame.f_code
|
||||
func_name = co.co_name
|
||||
line_no = frame.f_lineno
|
||||
print("{e} {f} {l}".format(
|
||||
e=event, f=func_name, l=line_no))
|
||||
return simple_tracer
|
||||
```
|
||||
|
||||
在分析函数时我们首先关注的是参数和返回值,该跟踪函数的参数分别是:
|
||||
|
||||
* **frame**,当前堆栈帧,它是包含当前函数执行时解释器里完整状态的对象
|
||||
* **event**,它是一个值可能为 **"call"**, **"line"**, **"return"**, 或 **"exception"** 的字符串
|
||||
* **arg**,它的取值基于 event 的类型,是一个可选项
|
||||
|
||||
|
||||
|
||||
该跟踪函数的返回值是它自身,这是由于解释器需要持续跟踪两类跟踪函数:
|
||||
|
||||
* **全局跟踪函数(每线程):** 该跟踪函数由当前线程调用 **sys.settrace** 来设置,并在解释器创建一个新 **frame** 时被调用(即代码中发生函数调用时)。虽然没有现成的方式来为不同的线程设置跟踪函数,但你可以调用 **threading.settrace** 来为所有新创建的 **threading** 模块线程设置跟踪函数。
|
||||
* **局部跟踪函数(每一帧):** 解释器将该跟踪函数的值设置为全局跟踪函数创建帧时的返回值。同样也没有现成的方法能够在帧被创建时自动设置局部跟踪函数。
|
||||
|
||||
|
||||
|
||||
该机制的目的是让调试器对被跟踪的帧有更精确的把握,以减少对性能的影响。
|
||||
|
||||
### 简单三步构建调试器 (我们最初的设想)
|
||||
|
||||
仅仅依靠上文提到的内容,用自制的跟踪函数来构建一个真正的调试器似乎有些不切实际。幸运的是,Python 的标准调试器 **pdb** 是基于 **Bdb** 构建的,后者是 Python 标准库中专门用于构建调试器的基类。
|
||||
|
||||
基于 **Bdb** 的简易断点调试器看上去是这样的:
|
||||
|
||||
|
||||
```
|
||||
import bdb
|
||||
import inspect
|
||||
|
||||
class Debugger(bdb.Bdb):
|
||||
def __init__(self):
|
||||
Bdb.__init__(self)
|
||||
self.breakpoints = dict()
|
||||
self.set_trace()
|
||||
|
||||
def set_breakpoint(self, filename, lineno, method):
|
||||
self.set_break(filename, lineno)
|
||||
try :
|
||||
self.breakpoints[(filename, lineno)].add(method)
|
||||
except KeyError:
|
||||
self.breakpoints[(filename, lineno)] = [method]
|
||||
|
||||
def user_line(self, frame):
|
||||
if not self.break_here(frame):
|
||||
return
|
||||
|
||||
# Get filename and lineno from frame
|
||||
(filename, lineno, _, _, _) = inspect.getframeinfo(frame)
|
||||
|
||||
methods = self.breakpoints[(filename, lineno)]
|
||||
for method in methods:
|
||||
method(frame)
|
||||
```
|
||||
|
||||
这个调试器类的全部构成是:
|
||||
|
||||
1. 继承 **Bdb**,定义一个简单的构造函数来初始化基类,并开始跟踪。
|
||||
2. 添加 **set_breakpoint** 方法,它使用 **Bdb** 来设置断点,并跟踪这些断点。
|
||||
3. 重载 **Bdb** 在当前用户行调用的 **user_line** 方法,该方法一定被一个断点调用,之后获取该断点的源位置,并调用已注册的断点。
|
||||
|
||||
|
||||
|
||||
### 这个简易的 Bdb 调试器效率如何呢?
|
||||
|
||||
Rookout 的目标是在生产级性能的使用场景下提供接近普通调试器的使用体验。那么,让我们来看看先前构建出来的简易调试器表现的如何。
|
||||
|
||||
为了衡量调试器的整体性能开销,我们使用如下两个简单的函数来进行测试,它们分别在不同的情景下执行了 1600 万次。请注意,在所有情景下断点都不会被执行。
|
||||
|
||||
|
||||
```
|
||||
def empty_method():
|
||||
pass
|
||||
|
||||
def simple_method():
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
d = 4
|
||||
e = 5
|
||||
f = 6
|
||||
g = 7
|
||||
h = 8
|
||||
i = 9
|
||||
j = 10
|
||||
```
|
||||
|
||||
在使用调试器的情况下需要大量的时间才能完成测试。糟糕的结果指明了,这个简陋 **Bdb** 调试器的性能还远不足以在生产环境中使用。
|
||||
|
||||
![First Bdb debugger results][6]
|
||||
|
||||
### 对调试器进行优化
|
||||
|
||||
降低调试器的额外开销主要有三种方法:
|
||||
|
||||
1. **尽可能的限制局部跟踪:** 由于每一行代码都可能包含大量事务,局部跟踪比全局跟踪的开销要大得多。
|
||||
2. **优化 "call" 事务并尽快将控制权还给解释器:** 在 **call** 事务发生时调试器的主要工作是判断是否需要对该事务进行跟踪。
|
||||
3. **优化 "line" 事务并尽快将控制权还给解释器:** 在 **line** 事务发生时调试器的主要工作是判断我们在此处是否需要设置一个断点。
|
||||
|
||||
|
||||
|
||||
于是我们克隆了 **Bdb** 项目,精简特征,简化代码,针对使用场景进行优化。这些工作虽然得到了一些效果,但仍无法满足我们的需求。因此我们又继续进行了其它的尝试,将代码优化并迁移至 **.pyx** 使用 [Cython][7] 进行编译,可惜结果(如下图所示)依旧不够理想。最终,我们在深入了解 CPython 源码之后意识到,让跟踪过程快到满足生产需求是不可能的。
|
||||
|
||||
![Second Bdb debugger results][8]
|
||||
|
||||
### 放弃 Bdb 转而尝试字节码操作
|
||||
|
||||
熬过先前对标准调试方法进行的试验-失败-再试验循环所带来的失望,我们将目光转向另一种选择:字节码操作。
|
||||
|
||||
Python 解释器的工作主要分为两个阶段:
|
||||
|
||||
1. **将 Python 源码编译成 Python 字节码:** 这种不可读(对人类而言)的格式专为执行的效率而优化,它们通常缓存在我们熟知的 **.pyc** 文件当中。
|
||||
2. **遍历 _interpreter loop_ 中的字节码:** 在这一步中解释器会逐条的执行指令
|
||||
|
||||
|
||||
|
||||
我们选择的模式是:使用**字节码操作**来设置没有全局额外开销的**不中断断点**。这种方式的实现首先需要在内存中的字节码里找到我们感兴趣的部分,然后在该部分的相关机器指令前插入一个函数调用。如此一来,解释器无需任何额外的工作即可实现我们的不中断断点。
|
||||
|
||||
这种方法并不依靠魔法来实现,让我们简要地举个例子。
|
||||
|
||||
首先定义一个简单的函数:
|
||||
|
||||
|
||||
```
|
||||
def multiply(a, b):
|
||||
result = a * b
|
||||
return result
|
||||
```
|
||||
|
||||
在 **[inspect][9]** 模块(其包含了许多实用的单元)的文档里,我们得知可以通过访问 **multiply.func_code.co_code** 来获取函数的字节码:
|
||||
|
||||
|
||||
```
|
||||
`'|\x00\x00|\x01\x00\x14}\x02\x00|\x02\x00S'`
|
||||
```
|
||||
|
||||
使用 Python 标准库中的 **[dis][10]** 模块可以翻译这些不可读的字符串。调用 **dis.dis(multiply.func_code.co_code)** 之后,我们就可以得到:
|
||||
|
||||
|
||||
```
|
||||
4 0 LOAD_FAST 0 (a)
|
||||
3 LOAD_FAST 1 (b)
|
||||
6 BINARY_MULTIPLY
|
||||
7 STORE_FAST 2 (result)
|
||||
|
||||
5 10 LOAD_FAST 2 (result)
|
||||
13 RETURN_VALUE
|
||||
```
|
||||
|
||||
与直截了当的解决方案相比,这种方法让我们更靠近发生在调试器背后的事情。可惜 Python 并没有提供在解释器中修改函数字节码的方法。我们可以对函数对象进行重写,不过那样做的效率满足不了大多数实际的调试场景。最后我们不得不采用一种迂回的方式来使用原生拓展才能完成这一任务。
|
||||
|
||||
### 总结
|
||||
|
||||
在构建一个新工具时,总会学到许多事情的工作原理。这种刨根问底的过程能够使你的思路跳出桎梏,从而得到意料之外的解决方案。
|
||||
|
||||
在 Rookout 团队中构建不中断断点的这段时间里,我学到了许多有关编译器、调试器、服务器框架、并发模型等等领域的知识。如果你希望更深入的了解字节码操作,谷歌的开源项目 **[cloud-debug-python][11]** 为编辑字节码提供了一些工具。
|
||||
|
||||
* * *
|
||||
|
||||
_Liran Haimovitch 将于 2019 年八月 17-18 日在旧金山举办的 [PyBay][3] 中发表题为 "[Understanding Python’s Debugging Internals][12]" 的演说,使用 [OpenSource35][13] 可以获得购票优惠,并使他们得知您是在我们的社区得知此事。_
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/8/debug-python
|
||||
|
||||
作者:[Liran Haimovitch][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[caiichenr](https://github.com/caiichenr)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/liranhaimovitch
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python_jungle_lead.jpeg?itok=pFKKEvT- (Real python in the graphic jungle)
|
||||
[2]: https://rookout.com/
|
||||
[3]: https://pybay.com/
|
||||
[4]: https://docs.python.org/3/library/sys.html#sys.settrace
|
||||
[5]: https://opensource.com/sites/default/files/uploads/python2docs.png (set_trace Python 2 docs page)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/debuggerresults1.png (First Bdb debugger results)
|
||||
[7]: https://cython.org/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/debuggerresults2.png (Second Bdb debugger results)
|
||||
[9]: https://docs.python.org/2/library/inspect.html
|
||||
[10]: https://docs.python.org/2/library/dis.html
|
||||
[11]: https://github.com/GoogleCloudPlatform/cloud-debug-python
|
||||
[12]: https://pybay.com/speaker/liran-haimovitch/
|
||||
[13]: https://ti.to/sf-python/pybay2019/discount/OpenSource35
|
@ -0,0 +1,142 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (HankChow)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Session: An Open Source Private Messenger That Doesn’t Need Your Phone Number)
|
||||
[#]: via: (https://itsfoss.com/session-messenger/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
Session:一款不需要电话号码的开源通信应用
|
||||
======
|
||||
|
||||
Signal 作为一款私人通信应用,正在变得愈发流行。而我们下面要介绍开源应用 Session 则是 Signal 的一个<ruby>复刻<rt>fork</rt></ruby>,它的一大亮点是并不需要提供手机号码即可以开始使用。
|
||||
|
||||
### Session:一款真正意义上的私人通信应用
|
||||
|
||||
![][1]
|
||||
|
||||
对于私人通信服务来说,有没有既能保护通信安全性,又尊重用户跨平台隐私的集大成者呢?很多注重个人隐私的用户似乎都在寻找这个问题的答案。
|
||||
|
||||
最近,我留意到 [Loki Foundation][3] 开发的一款叫做 [Session][2] 的开源通信应用。从技术上来说,Session 是另一款[开源、加密的通信应用 Signal][4] 的一个复刻。
|
||||
|
||||
在本文中,我会讲述我自己使用 Session 的体验,以及 Session 的一些主要功能。
|
||||
|
||||
Session 在这个领域中算是一款比较新的应用了,因此我还会在文章的最后提到它的一些不足之处。
|
||||
|
||||
### Session 的一些主要功能
|
||||
|
||||
接下来我会重点介绍 Session 的主要功能,可以供你参考这款应用是否值得使用。
|
||||
|
||||
#### Session 的使用过程中不需要提供手机号码
|
||||
|
||||
![][5]
|
||||
|
||||
在 Signal 或者其它类似的通信应用中,用户都需要提供手机号码才得以成功注册。注重隐私的用户们都认为这样的做法会潜藏着巨大的安全隐患。
|
||||
|
||||
而使用 Session 则简单得多。在 PC 或手机上安装应用之后,只需要点击“<ruby>创建账号<rt>Create Account</rt></ruby>”,无须提供手机号码,它就会生成一个类似 **05652245af9a8bfee4f5a8138fd5c……..** 这样的随机且唯一的 Session ID。
|
||||
|
||||
此后,把 Session ID 分享给想要添加的联系人就可以了。Session 还支持二维码,其他人可以通过扫描二维码添加你的 Session ID 为好友。
|
||||
|
||||
#### Session 使用了区块链等加密技术
|
||||
|
||||
![Session ID][6]
|
||||
|
||||
对[区块链][7]有所了解的用户都很期待区块链能为普罗大众做出什么有实际意义的应用,而 Session 可以算得上其中一个。尽管 Session 的核心是基于区块链的,但普通用户在使用时并不需要真正弄懂区块链。
|
||||
|
||||
如果你好奇它的工作原理,可以参考这篇[官方的博客文章][8],里面有相关的解释。
|
||||
|
||||
#### 跨平台支持
|
||||
|
||||
![][9]
|
||||
|
||||
这样严格保护隐私的应用,是否能在不同平台上使用?
|
||||
|
||||
答案是肯定的。首先,它支持 Linux 和 Android 平台,同时也支持 Windows/Mac/iOS 平台。因此跨平台、跨设备的消息同步是没有问题的。
|
||||
|
||||
#### 包含基本隐私选项
|
||||
|
||||
![][10]
|
||||
|
||||
毫无疑问,基本的隐私功能是必须有的,这是作为一个以安全为卖点的应用所必备的体验。
|
||||
|
||||
最基本的选项包括:
|
||||
|
||||
* **消息有效期**:你可以控制一条消息在接收者阅读前的保留时长
|
||||
* **已读回执**:消息发送者可以知晓你已经阅读该消息
|
||||
|
||||
|
||||
|
||||
#### Session 使用去中心化网络保护你的元数据
|
||||
|
||||
尽管 Session 不使用<ruby>端对端<rt>peer-to-peer</rt></ruby>技术,但它也不适用中心化的服务器。
|
||||
|
||||
Session 采用了去中心化的架构实现消息的传输和路由。如果你不熟悉这方面的内容,可以关注 Session 的官方博客,尝试了解[中心化网络和去中心化网络的区别][11],以及它的实际工作原理。
|
||||
|
||||
同时,这样的网络架构还有助于保护诸如与 IP 地址相关的信息等元数据。
|
||||
|
||||
#### 其它功能
|
||||
|
||||
除了专注于隐私之外,Session 也支持群聊、语音消息、发送附件等通信应用的基本功能。
|
||||
|
||||
### 在 Linux 上安装 Session
|
||||
|
||||
在[官方下载页面][12]中可以下载到对应的 .AppImage 文件。如果你不了解这个文件的使用方法,可以查阅我们的[相关文章][13]。
|
||||
|
||||
另外,你也可以在它的 [Github 发布页面][14] 获取到对应的 .deb 安装文件。
|
||||
|
||||
[下载 Session][12]
|
||||
|
||||
### 我使用 Session 的体验
|
||||
|
||||
我在各种平台上都试用过 Session,其中在 PC 上我使用了 Pop!_OS 19.10 的 .AppImage 文件运行这个应用。
|
||||
|
||||
总的来说,使用的体验很不错,用户界面也没有出现问题。
|
||||
|
||||
在设置中备份了密码(也称为<ruby>种子<rt>seed</rt></ruby>)后,可以很方便地恢复账号。
|
||||
|
||||
![][15]
|
||||
|
||||
当然,我也发现了一些需要改进的地方:
|
||||
|
||||
* 在接受好友请求时会出现延迟
|
||||
* 设备间连接的方式不太直观
|
||||
* 当你在不同的设备上使用同一个 Session ID 向同一个人回复消息时,对方会收到两个不同的对话
|
||||
|
||||
|
||||
|
||||
### 总结
|
||||
|
||||
当然,最完美的事物是不存在的。我也会一直使用 Session 并考虑它发展的方向,这是一个注重引得的用户应该做的事情。
|
||||
|
||||
欢迎在评论区发表你的看法。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/session-messenger/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[HankChow](https://github.com/HankChow)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-app.jpg?ssl=1
|
||||
[2]: https://getsession.org/
|
||||
[3]: https://loki.foundation/
|
||||
[4]: https://itsfoss.com/signal-messaging-app/
|
||||
[5]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-create.jpg?ssl=1
|
||||
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/03/session-application-id.jpg?ssl=1
|
||||
[7]: https://en.wikipedia.org/wiki/Blockchain
|
||||
[8]: https://getsession.org/how-session-protects-your-anonymity-with-blockchain-and-crypto/
|
||||
[9]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-cross-platform.jpg?ssl=1
|
||||
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-settings.jpg?fit=800%2C512&ssl=1
|
||||
[11]: https://getsession.org/centralisation-vs-decentralisation-in-private-messaging/
|
||||
[12]: https://getsession.org/download/
|
||||
[13]: https://itsfoss.com/use-appimage-linux/
|
||||
[14]: https://github.com/loki-project/session-desktop/releases
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-seed.jpg?ssl=1
|
Loading…
Reference in New Issue
Block a user