https://www.wangmin.info/ zh-CN 正在输出... Fri, 31 Mar 2017 16:02:00 +0800 Fri, 31 Mar 2017 16:02:00 +0800 start kernel 之后没有任何输出 https://www.wangmin.info/recommend/527.html https://www.wangmin.info/recommend/527.html Fri, 31 Mar 2017 16:02:00 +0800 admin 一、对此一般有多种调试方法与调查方向,可能的原因如下:
1、串口的引脚是否配置正确,例如pincltrl指定的Debug串口引脚,串口选错没有
2、串口的直连与交叉问题
3、查看bootargs传过去的console=是否正确,例如ttyXX是否正确,波特率
4、内核使用的command Line是uboot的还是内核的,还是dtb中chosen字段中的

二、调查方法串口硬件问题的调查可以使用示波器与逻辑分析仪来确认

三、串口软件配置问题的调查可以使用在uboot查看log_buf的方法来查看问题出在哪里
当内核在start kernel之后,没有任何输出,等一会于用reset按键软reset,并停在uboot命令行中,使用下面方法来查看kenrel的log_buf,即printk存储log的地方。
在内核编译目录下面的System.map中找到__log_buf的位置,例如:
这个表示log_buf位于内核虚拟地址0x80dcdd84的位置,这个地方是直接映射段,因此对于imx6而言就是0x10dcdd84。
于是在uboot中使用md命令来查看这段区域的内容:
uart1.png

然后一直回车,最后可以看到内核最后使用的bootargs/commandLine:
uart2.png

kernel command line传入新的内核支持四种方式来组成commandline:
1、使用uboot中的
2、使用内核配置中的
3、使用uboot+内核配置中的
4、使用dtb中的chosen中的bootargs
这些都在menuconfig中可以看到,因此如果你在内核中看到的commandline与自己从uboot中传入的不一样,那么检查下面选项:
uart3.png

]]>
0 https://www.wangmin.info/recommend/527.html#comments https://www.wangmin.info/feed/recommend/527.html
How to Deploy Google BBR on CentOS 7 in GCP https://www.wangmin.info/recommend/centos_7_bbr_gcp.html https://www.wangmin.info/recommend/centos_7_bbr_gcp.html Wed, 22 Mar 2017 16:21:00 +0800 admin BBR (Bottleneck Bandwidth and RTT) is a new congestion control algorithm which is contributed to the Linux kernel TCP stack by Google. With BBR in place, a Linux server can get significantly increased throughput and reduced latency for connections. Besides, it's easy to deploy BBR because this algorithm requires only updates on the sender side, not in the network or on the receiver side.

In this article, I will show you how to deploy BBR on a Vultr CentOS 7 KVM server instance.

Prerequisites

A Vultr CentOS 7 x64 server instance.
A sudo user.

Step 1: Upgrade the kernel using the ELRepo RPM repository

In order to use BBR, you need to upgrade the kernel of your CentOS 7 machine to 4.9.0. You can easily get that done using the ELRepo RPM repository.

Before the upgrade, you can take a look at the current kernel:

uname -r
This command should output a string which resembles:

3.10.0-514.2.2.el7.x86_64
As you see, the current kernel is 3.10.0.

Install the ELRepo repo:

**sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
sudo rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm**
Install the 4.9.0 kernel using the ELRepo repo:

sudo yum --enablerepo=elrepo-kernel install kernel-ml -y
Confirm the result:

rpm -qa | grep kernel
If the installation is successful, you should see kernel-ml-4.9.0-1.el7.elrepo.x86_64 among the output list:

kernel-ml-4.9.0-1.el7.elrepo.x86_64
kernel-3.10.0-514.el7.x86_64
kernel-tools-libs-3.10.0-514.2.2.el7.x86_64
kernel-tools-3.10.0-514.2.2.el7.x86_64
kernel-3.10.0-514.2.2.el7.x86_64
Now, you need to enable the 4.9.0 kernel by setting up the default grub2 boot entry.

Show all entries in the grub2 menu:

sudo egrep ^menuentry /etc/grub2.cfg | cut -f 2 -d \'
The result should resemble:

CentOS Linux 7 Rescue a0cbf86a6ef1416a8812657bb4f2b860 (4.9.0-1.el7.elrepo.x86_64)
CentOS Linux (4.9.0-1.el7.elrepo.x86_64) 7 (Core)
CentOS Linux (3.10.0-514.2.2.el7.x86_64) 7 (Core)
CentOS Linux (3.10.0-514.el7.x86_64) 7 (Core)
CentOS Linux (0-rescue-bf94f46c6bd04792a6a42c91bae645f7) 7 (Core)
Since the line count starts at 0 and the 4.9.0 kernel entry is on the second line, set the default boot entry as 1:

sudo grub2-set-default 1
Reboot the system:

sudo shutdown -r now
When the server is back online, log back in and rerun the uname command to confirm that you are using the correct Kernel:

uname -r
You should see the result as below:

4.9.0-1.el7.elrepo.x86_64

Step 2: Enable BBR

In order to enable the BBR algorithm, you need to modify the sysctl configuration as follows:

**echo 'net.core.default_qdisc=fq' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv4.tcp_congestion_control=bbr' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p**
Now, you can use the following commands to confirm that BBR is enabled:

sudo sysctl net.ipv4.tcp_available_congestion_control
The output should resemble:

net.ipv4.tcp_available_congestion_control = bbr cubic reno
Next, verify with:

sudo sysctl -n net.ipv4.tcp_congestion_control
The output should be:

bbr
Finally, check that the kernel module was loaded:

lsmod | grep bbr
The output will be similar to:

tcp_bbr 16384 0

Step 3 (optional): Test the network performance enhancement

In order to test BBR's network performance enhancement, you can create a file in the web server directory for download, and then test the download speed from a web browser on your desktop machine.

**sudo yum install httpd -y
sudo systemctl start httpd.service
sudo firewall-cmd --zone=public --permanent --add-service=http
sudo firewall-cmd --reload
cd /var/www/html
sudo dd if=/dev/zero of=500mb.zip bs=1024k count=500**
Finally, visit the URL http://[your-server-IP]/500mb.zip from a web browser on your desktop computer, and then evaluate download speed.

That's all. Thank you for reading.

]]>
0 https://www.wangmin.info/recommend/centos_7_bbr_gcp.html#comments https://www.wangmin.info/feed/recommend/centos_7_bbr_gcp.html
How to Deploy Google BBR on CentOS 6 in GCP https://www.wangmin.info/recommend/centos_6_bbr_on_gcp.html https://www.wangmin.info/recommend/centos_6_bbr_on_gcp.html Wed, 22 Mar 2017 16:12:00 +0800 admin BBR (Bottleneck Bandwidth and RTT) is a new congestion control algorithm which is contributed to the Linux kernel TCP stack by Google. With BBR in place, a Linux server can get significantly increased throughput and reduced latency for connections. Besides, it's easy to deploy BBR because this algorithm requires only updates on the sender side, not in the network or on the receiver side.

In this article, I will show you how to deploy BBR on a Vultr CentOS 7 KVM server instance.

Prerequisites

A Vultr CentOS 6 x64 server instance.
A sudo user.

Step 1: Upgrade the kernel using the ELRepo RPM repository

In order to use BBR, you need to upgrade the kernel of your CentOS 7 machine to 4.9.0. You can easily get that done using the ELRepo RPM repository.

Before the upgrade, you can take a look at the current kernel:

uname -r
This command should output a string which resembles:

2.6.32-642.15.1.el6.x86_64
As you see, the current kernel is 2.6.32.

Install the ELRepo repo:

sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
sudo rpm -Uvh http://www.elrepo.org/elrepo-release-6-6.el6.elrepo.noarch.rpm
Install the 4.10.4 kernel using the ELRepo repo:

sudo yum --enablerepo=elrepo-kernel install kernel-ml -y
Confirm the result:

rpm -qa | grep kernel
If the installation is successful, you should see kernel-ml-4.10.4-1.el6.elrepo.x86_64 among the output list:

dracut-kernel-004-409.el6_8.2.noarch
kernel-2.6.32-573.el6.x86_64
kernel-ml-4.10.4-1.el6.elrepo.x86_64
kernel-headers-2.6.32-642.15.1.el6.x86_64
abrt-addon-kerneloops-2.0.8-40.el6.centos.x86_64
kernel-2.6.32-642.15.1.el6.x86_64
kernel-firmware-2.6.32-642.15.1.el6.noarch
libreport-plugin-kerneloops-2.0.9-32.el6.centos.x86_6

Now, you need to enable the 4.10.4 kernel by setting up the default grub boot entry.

Show all entries in the grub2 menu:

sudo sed -i 's:default=.*:default=0:g' /etc/grub.conf

Reboot the system:

sudo shutdown -r now
When the server is back online, log back in and rerun the uname command to confirm that you are using the correct Kernel:

uname -r
You should see the result as below:

4.10.4-1.el6.elrepo.x86_64

Step 2: Enable BBR

In order to enable the BBR algorithm, you need to modify the sysctl configuration as follows:

echo 'net.core.default_qdisc=fq' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv4.tcp_congestion_control=bbr' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Now, you can use the following commands to confirm that BBR is enabled:

sudo sysctl net.ipv4.tcp_available_congestion_control
The output should resemble:

net.ipv4.tcp_available_congestion_control = bbr cubic reno
Next, verify with:

sudo sysctl -n net.ipv4.tcp_congestion_control
The output should be:

bbr
Finally, check that the kernel module was loaded:

lsmod | grep bbr
The output will be similar to:

tcp_bbr 16384 0

Step 3 (optional): Test the network performance enhancement

In order to test BBR's network performance enhancement, you can create a file in the web server directory for download, and then test the download speed from a web browser on your desktop machine.

sudo yum install httpd -y
sudo server httpd start
cd /var/www/html
sudo dd if=/dev/zero of=500mb.zip bs=1024k count=500
Finally, visit the URL http://[your-server-IP]/500mb.zip from a web browser on your desktop computer, and then evaluate download speed.

That's all. Thank you for reading.

]]>
0 https://www.wangmin.info/recommend/centos_6_bbr_on_gcp.html#comments https://www.wangmin.info/feed/recommend/centos_6_bbr_on_gcp.html
android studio gradle的问题 https://www.wangmin.info/app/use-default-gradle-wrapper.html https://www.wangmin.info/app/use-default-gradle-wrapper.html Mon, 20 Feb 2017 14:37:00 +0800 admin 1、相信大家都遇到每次升级了android studio之后,gradle又要同步的这个痛苦过程,因为gradle被墙,所以只能用其他办法下载压缩包。
2、自定义gradle路径每次都要麻烦一下,这次采用官方推荐的办法,不知道会不会也存在一样的问题,如下图所示:
gradle.png
3、下载gradle并配置
gradle2.png
下载下来的安装包放到gradle配置的相应目录,默认如下图,注意对应的版本号和路径
gradle3.png

]]>
0 https://www.wangmin.info/app/use-default-gradle-wrapper.html#comments https://www.wangmin.info/feed/app/use-default-gradle-wrapper.html
将程序从windows移植到linux(信号量和事件) https://www.wangmin.info/recommend/win2linux-sem-event.html https://www.wangmin.info/recommend/win2linux-sem-event.html Wed, 30 Nov 2016 14:57:00 +0800 admin 关于复杂的多线程和多进程应用程序的映射指南 随着开发人员将一些普及的 Windows® 应用程序迁移到 Linux™ 平台,企业中正在进行的向开放源码迁移的浪潮有可能引发极大的移植问题。这个由三部分组成的系列文章提供了一个映射指南,并附有一些例子,以简化从 Windows 到 Linux 的转移。本文是系列文章的第 2 部分,将介绍两种同步对象类型:信号量和事件。

当前,很多全球商务和服务都正在走向开源 —— 业界的所有主要参与者都在争取实现此目标。这一趋势催生了一个重要的迁移模式:为不同平台(Windows、OS2、Solaris 等)维持的许多现有产品都将被移植到开放源码的 Linux 平台。
很多应用程序在设计时并未考虑到需要将它们移植到 Linux。这有可能使移植成为一件痛苦的事情,但并非绝对如此。本系列文章的目的是,帮助您将涉及到 IPC 和线程原语的复杂应用程序从 Windows 迁移到 Linux。我们与您分享迁移这些关键应用程序的经验,其中包括要求线程同步的多线程应用程序以及要求进程间同步的多进程应用程序。
简言之,可以将此系列文章看作是一个映射文档 —— 它提供了与线程、进程和进程间通信元素(互斥、信号量等等)相关的各种 Windows 调用到 Linux 调用的映射。我们将那些映射分为三部分:
在 第 1 部分 中,我们已经对进程和线程进行了讨论。
本文将介绍信号量和事件。
第 3 部分将介绍互斥、临界区和等待函数。
在本文中,我们将从同步技术入手,继续从 Windows 到 Linux 的映射指导。
同步
在 Windows 上,同步是使用等待函数中的同步对象来实现的。同步对象可以有两种状态:有信号(signaled)状态和无信号(non-signaled)状态。当在一个等待函数中使用同步对象时,等待函数就会阻塞调用线程,直到同步对象的状态被设置为有信号为止。
下面是在 Windows 上可以使用的一些同步对象:
事件(Event)
信号量(Semaphore)
互斥(Mutexe)
临界区(Critical section)
在 Linux 中,可以使用不同的同步原语。Windows 与 Linux 的不同之处在于每个原语都有自己的等待函数(所谓等待函数就是用来修改同步原语状态的函数);在 Windows 中,有一些通用的等待函数来实现相同的目的。以下是 Linux 上可以使用的一些同步原语:
信号量(Semaphore)
条件变量(Conditional variable)
互斥(Mutexe)
通过使用上面列出的这些原语,各种库都可以用于 Linux 之上,以提供同步机制。
3.jpg
信号量
Windows 信号量是一些计数器变量,允许有限个线程/进程访问共享资源。Linux POSIX 信号量也是一些计数器变量,可以用来在 Linux 上实现 Windows 上的信号量功能。
在对进程进行映射时,我们需要考虑以下问题:
信号量的类型: Windows 提供了有名(named)信号量和无名(unnamed)信号量。有名信号量可以在进程之间进行同步。在 Linux 上,在相同进程的不同线程之间,则只使用 POSIX 信号量。在进程之间,可以使用 System V 信号量。
等待函数中的超时: 当在一个等待函数中使用时,可以为 Windows 信号量对象指定超时值。在 Linux 中,并没有提供这种功能,只能通过应用程序逻辑处理超时的问题。
4.jpg
创建信号量
在 Windows 中,可以使用 CreateSemaphore() 创建或打开一个有名或无名的信号量。

HANDLE CreateSemaphore(
  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
  LONG lInitialCount,
  LONG lMaximumCount,
  LPCTSTR lpName
);

在这段代码中:
lpSemaphoreAttributes 是一个指向安全性属性的指针。如果这个指针为空,那么这个信号量就不能被继承。
lInitialCount 是该信号量的初始值。
lMaximumCount 是该信号量的最大值,该值必须大于 0。
lpName 是信号量的名称。如果该值为 NULL,那么这个信号量就只能在相同进程的不同线程之间共享。否则,就可以在不同的进程之间进行共享。
这个函数创建信号量,并返回这个信号量的句柄。它还将初始值设置为调用中指定的值。这样就可以允许有限个线程来访问某个共享资源。
在 Linux 中,可以使用 sem_init() 来创建一个无名的 POSIX 信号量,这个调用可以在相同进程的线程之间使用。它还会对信号量计数器进行初始化:int sem_init(sem_t *sem, int pshared, unsigned int value)。在这段代码中:
value(信号量计数器)是这个信号量的初始值。
pshared 可以忽略,因为在目前的实现中,POSIX 信号量还不能在进程之间进行共享。
这里要注意的是,最大值基于 demaphore.h 头文件中定义的 SEM_VALUE_MAX。
在 Linux 中,semget() 用于创建 System V 信号量,它可以在不同集成的线程之间使用。可以用它来实现与 Windows 中有名信号量相同的功能。这个函数返回一个信号量集标识符,它与一个参数的键值关联在一起。当创建一个新信号量集时,对于与 semid_ds 数据结构关联在一起的信号量,semget() 要负责将它们进行初始化,方法如下:
sem_perm.cuid 和 sem_perm.uid 被设置为调用进程的有效用户 ID。
sem_perm.cgid 和 sem_perm.gid 被设置为调用进程的有效组 ID。
sem_perm.mode 的低 9 位被设置为 semflg 的低 9 位。
sem_nsems 被设置为 nsems 的值。
sem_otime 被设置为 0。
sem_ctime 被设置为当前时间。
用来创建 System V 信号量使用的代码是:int semget(key_t key, int nsems, int semflg)。下面是对这段代码的一些解释:
key 是一个惟一的标识符,不同的进程使用它来标识这个信号量集。我们可以使用 ftok() 生成一个惟一的键值。IPC_PRIVATE 是一个特殊的 key_t 值;当使用 IPC_PRIVATE 作为 key 时,这个系统调用就会只使用 semflg 的低 9 位,但却忽略其他内容,从而新创建一个信号量集(在成功时)。
nsems 是这个信号量集中信号量的数量。
semflg 是这个新信号量集的权限。要新创建一个信号量集,您可以将使用 IPC_CREAT 来设置位操作或访问权限。如果具有该 key 值的信号量集已经存在,那么 IPC_CREAT/IPC_EXCL 标记就会失败。
注意,在 System V 信号量中,key 被用来惟一标识信号量;在 Windows 中,信号量是使用一个名称来标识的。
为了对信号量集数据结构进行初始化,可以使用 IPC_SET 命令来调用 semctl() 系统调用。将 arg.buf 所指向的 semid_ds 数据结构的某些成员的值写入信号量集数据结构中,同时更新这个结构的 sem_ctime member 的值。用户提供的这个 arg.buf 所指向的 semid_ds 结构如下所示:
sem_perm.uid
sem_perm.gid
sem_perm.mode (只有最低 9 位有效)
调用进程的有效用户 ID 应该是超级用户,或者至少应该与这个信号量集的创建者或所有者匹配: int semctl(int semid, int semnum, int cmd = IPC_SET, ...)。在这段代码中:
semid 是信号量集的标识符。
semnum 是信号量子集偏移量(从 0 到 nsems -1,其中 n 是这个信号量集中子集的个数)。这个命令会被忽略。
cmd 是命令;它使用 IPC_SET 来设置信号量的值。
args 是这个信号量集数据结构中要通过 IPC_SET 来更新的值(在这个例子中会有解释)。
最大计数器的值是根据在头文件中定义的 SEMVMX 来决定的。
打开信号量
在 Windows 中,我们使用 OpenSemaphore() 来打开某个指定信号量。只有在两个进程之间共享信号量时,才需要使用信号量。在成功打开信号量之后,这个函数就会返回这个信号量的句柄,这样就可以在后续的调用中使用它了。

HANDLE OpenSemaphore(
  DWORD dwDesiredAccess,
  BOOL bInheritHandle,
  LPCTSTR lpName
)

在这段代码中:
dwDesiredAccess 是针对该信号量对象所请求的访问权。
bInheritHandle 是用来控制这个信号量句柄是否可继承的标记。如果该值为 TRUE,那么这个句柄可以被继承。
lpName 是这个信号量的名称。
在 Linux 中,可以调用相同的 semget() 来打开某个信号量,不过此时 semflg 的值为 0:int semget(key,nsems,0)。在这段代码中:
key 应该指向想要打开的信号量集的 key 值。
为了打开一个已经存在的信号量,可以将 nsems 和标记设置为 0。semflg 值是在返回信号量集标识符之前对访问权限进行验证时设置的。
获取信号量
在 Windows 中,等待函数提供了获取同步对象的机制。可以使用的等待函数有多种类型;在这一节中,我们只考虑 WaitForSingleObject()(其他类型将会分别进行讨论)。这个函数使用一个信号量对象的句柄作为参数,并会一直等待下去,直到其状态变为有信号状态或超时为止。
DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );
在这段代码中:
hHandle 是指向互斥句柄的指针。
dwMilliseconds 是超时时间,以毫秒为单位。如果该值是 INFINITE,那么它阻塞调用线程/进程的时间就是不确定的。
在 Linux 中,sem_wait() 用来获取对信号量的访问。这个函数会挂起调用线程,直到这个信号量有一个非空计数为止。然后,它可以原子地减少这个信号量计数器的值:int sem_wait(sem_t * sem)。
在 POSIX 信号量中并没有超时操作。这可以通过在一个循环中执行一个非阻塞的 sem_trywait() 实现,该函数会对超时值进行计算:int sem_trywait(sem_t * sem)。
在使用 System V 信号量时,如果通过使用 IPC_SET 命令的 semctl() 调用设置初始的值,那么必须要使用 semop() 来获取信号量。semop() 执行操作集中指定的操作,并阻塞调用线程/进程,直到信号量值为 0 或更大为止:int semop(int semid, struct sembuf *sops, unsigned nsops)。
函数 semop() 原子地执行在 sops 中所包含的操作 —— 也就是说,只有在这些操作可以同时成功执行时,这些操作才会被同时执行。sops 所指向的数组中的每个 nsops 元素都使用 struct sembuf 指定了一个要对信号量执行的操作,这个结构包括以下成员:
unsigned short sem_num; (信号量个数)
short sem_op; (信号量操作)
short sem_flg; (操作标记)
要获取信号量,可以通过将 sem_op 设置为 -1 来调用 semop();在使用完信号量之后,可以通过将 sem_op 设置为 1 来调用 semop() 释放信号量。通过将 sem_op 设置为 -1 来调用 semop(),信号量计数器将会减小 1,如果该值小于 0(信号量的值是不能小于 0 的),那么这个信号量就不能再减小,而是会让调用线程/进程阻塞,直到其状态变为有信号状态为止。
sem_flg 中可以识别的标记是 IPC_NOWAIT 和 SEM_UNDO。如果某一个操作被设置了 SEM_UNDO 标记,那么在进程结束时,该操作将被取消。如果 sem_op 被设置为 0,那么 semop() 就会等待 semval 变成 0。这是一个“等待为 0” 的操作,可以用它来获取信号量。
记住,超时操作在 System V 信号量中并不适用。这可以在一个循环中使用非阻塞的 semop()(通过将 sem_flg 设置为 IPC_NOWAIT)实现,这会计算超时的值。
释放信号量
在 Windows 中,ReleaseSemaphore() 用来释放信号量。

BOOL ReleaseSemaphore(
  HANDLE hSemaphore,
  LONG lReleaseCount,
  LPLONG lpPreviousCount
);

在这段代码中:
hSemaphore 是一个指向信号量句柄的指针。
lReleaseCount 是信号量计数器,可以通过指定的数量来增加计数。
lpPreviousCount 是指向上一个信号量计数器返回时的变量的指针。如果并没有请求上一个信号量计数器的值,那么这个参数可以是 NULL。
这个函数会将信号量计数器的值增加在 lReleaseCount 中指定的值上,然后将这个信号量的状态设置为有信号状态。
在 Linux 中,我们使用 sem_post() 来释放信号量。这会唤醒对这个信号量进行阻塞的所有线程。信号量的计数器同时被增加 1。要为这个信号量的计数器添加指定的值(就像是 Windows 上一样),可以使用一个互斥变量多次调用以下函数:int sem_post(sem_t * sem)。
对于 System V 信号量来说,只能使用 semop() 来释放信号量:int semop(int semid, struct sembuf *sops, unsigned nsops)。
函数 semop() 原子地执行 sops 中包含的一组操作(只在所有操作都可以同时成功执行时,才会将所有的操作同时一次执行完)。sops 所指向的数组中的每个 nsops 元素都使用一个 struct sembuf 结构指定了一个要对这个信号量执行的操作,该结构包含以下元素:
unsigned short sem_num;(信号量个数)
short sem_op; (信号量操作)
short sem_flg; (操作标记)
要释放信号量,可以通过将 sem_op 设置为 1 来调用 semop()。通过将 semop() 设置为 1 来调用 semop(),这个信号量的计数器会增加 1,同时用信号通知这个信号量。
关闭/销毁信号量
在 Windows 中,我们使用 CloseHandle() 来关闭或销毁信号量对象。

BOOL CloseHandle(
  HANDLE hObject
);

hObject 是指向这个同步对象句柄的指针。
在 Linux 中,sem_destroy() 负责销毁信号量对象,并释放它所持有的资源: int sem_destroy(sem_t *sem)。对于 System V 信号量来说,只能使用 semctl() 函数的 IPC_RMID 命令来关闭信号量集:int semctl(int semid, int semnum, int cmd = IPC_RMID, ...)。
这个命令将立即删除信号量集及其数据结构,并唤醒所有正在等待的进程(如果发生错误,则返回,并将 errno 设置为 EIDRM)。调用进程的有效用户 ID 必须是超级用户,或者可以与该信号量集的创建者或所有者匹配的用户。参数 semnum 会被忽略。
例子
下面是信号量的几个例子。
清单 1. Windows 无名信号量的代码

HANDLE hSemaphore;
LONG   lCountMax = 10;
LONG   lPrevCount;
DWORD  dwRetCode;
// Create a semaphore with initial and max. counts of 10.
hSemaphore = CreateSemaphore(
                      NULL,        // no security attributes
                      0,           // initial count
                      lCountMax,   // maximum count
                      NULL);       // unnamed semaphore
// Try to enter the semaphore gate.
dwRetCode = WaitForSingleObject(
                   hSemaphore,  // handle to semaphore
                   2000L);   // zero-second time-out interval
switch (dwRetCode)
{
    // The semaphore object was signaled.
    case WAIT_OBJECT_0:
        // Semaphore is signaled
        // go ahead and continue the work
        goto success:
        break;
    case WAIT_TIMEOUT:
        // Handle the time out case
        break;
}
Success:
// Job done, release the semaphore
ReleaseSemaphore(
        hSemaphore,  // handle to semaphore
        1,           // increase count by one
        NULL)        // not interested in previous count
// Close the semaphore handle
CloseHandle(hSemaphore);

清单 2. Linux 使用 POSIX 信号量的等效代码

// Main thread
#define TIMEOUT 200  /* 2 secs */
// Thread 1
sem_t sem     ; // Global Variable
int   retCode ;
// Initialize event semaphore
retCode = sem_init(
                   sem,   // handle to the event semaphore
                   0,     // not shared
                   0);    // initially set to non signaled state
while (timeout < TIMEOUT ) {
   delay.tv_sec = 0;
   delay.tv_nsec = 1000000;  /* 1 milli sec */
   // Wait for the event be signaled
   retCode = sem_trywait(
                   &sem); // event semaphore handle
                          // non blocking call
   if (!retCode)  {
        /* Event is signaled */
        break;
   }
   else {
       /* check whether somebody else has the mutex */
       if (retCode == EPERM ) {
            /* sleep for delay time */
            nanosleep(&delay, NULL);
            timeout++ ;
       }
       else{
           /* error  */
       }
   }
}
// Completed the job,
// now destroy the event semaphore
retCode = sem_destroy(
                      &sem);   // Event semaphore handle
// Thread 2
// Condition met
// now signal the event semaphore
sem_post(
         &sem);    // Event semaphore Handle

清单 3. Linux 使用 System V 信号量的等效代码

// Process 1
#define TIMEOUT 200
//Definition of variables
    key_t key;
    int semid;
    int Ret;
    int timeout = 0;
    struct sembuf operation[1] ;
    union semun
    {
        int val;
        struct semid_ds *buf;
        USHORT *array;
    } semctl_arg,ignored_argument;
    key = ftok(); // Generate a unique key, U can also supply a value instead
    semid = semget(key,             // a unique identifier to identify semaphore set
                    1,              // number of semaphore in the semaphore set
                   0666 | IPC_CREAT // permissions (rwxrwxrwx) on the new
                                    //    semaphore set and creation flag
                    );
   //Set Initial value for the resource
    semctl_arg.val = 0; //Setting semval to 0
    semctl(semid, 0, SETVAL, semctl_arg);
    //Wait for Zero
    while(timeout < TIMEOUT)
    {
        delay.tv_sec = 0;
        delay.tv_nsec = 1000000;  /* 1 milli sec */
        //Call Wait for Zero with IPC_NOWAIT option,so it will be non blocking
        operation[0].sem_op = -1; // Wait until the semaphore count becomes 0
        operation[0].sem_num = 0;
        operation[0].sem_flg = IPC_NOWAIT;
        ret = semop(semid, operation,1);
        if(ret < 0)
        {
            /* check whether somebody else has the mutex */
            if (retCode == EPERM )
            {
                /* sleep for delay time */
                nanosleep(&delay, NULL);
                timeout++ ;
            }
            else
            {
                printf("ERROR while wait ");
                break;
            }
        }
        else
        {
            /*semaphore got triggered */
            break;
        }
    }
    //Close semaphore
    iRc = semctl(semid, 1, IPC_RMID , ignored_argument);
}
// Process 2
key_t key = KEY; // Process 2 should know key value in order to open the
                 //    existing semaphore set
    struct sembuf operation[1] ;
    //Open semaphore
    semid = semget(key, 1, 0);
    operation[0].sem_op = 1; // Release the resource so Wait in process 1 will
                             //    be triggered
    operation[0].sem_num = 0;
    operation[0].sem_flg = SEM_UNDO;
    //Release semaphore
    semop(semid, operation,0);
}

事件
在 Windows 中,事件对象是那些需要使用 SetEvent() 函数显式地将其状态设置为有信号状态的同步对象。事件对象来源有两种类型:
在 手工重置事件(manual reset event) 中,对象的状态会一直维持为有信号状态,直到使用 ResetEvent() 函数显式地重新设置它为止。
在 自动重置事件(auto reset event) 中,对象的状态会一直维持为有信号状态,直到单个正在等待的线程被释放为止。当正在等待的线程被释放时,其状态就被设置为无信号的状态。
事件对象有两种状态,有信号(signaled)状态 和 无信号(non-signaled)状态。对事件对象调用的等待函数会阻塞调用线程,直到其状态被设置为有信号状态为止。
在进行平台的迁移时,需要考虑以下问题:
Windows 提供了 有名(named) 和 无名(un-named) 的事件对象。有名事件对象用来在进程之间进行同步,而在 Linux 中, pthreads 和 POSIX 都提供了线程间的同步功能。为了在 Linux 实现与 Windows 中有名事件对象相同的功能,可以使用 System V 信号量或信号。
Windows 提供了两种类型的事件对象 —— 手工重置对象和自动重置对象。Linux 只提供了自动重置事件的特性。
在 Windows 中,事件对象的初始状态被设置为有信号状态。在 Linux 中,pthreads 并没有提供初始状态,而 POSIX 信号量则提供了一个初始状态。
Windows 事件对象是异步的。在 Linux 中,POSIX 信号量和 System V 信号量也都是异步的,不过 pthreads 条件变量不是异步的。
当在一个等待函数中使用事件对象时,可以指定 Windows 的事件对象的超时时间值。在 Linux 中,只有 pthreads 在等待函数中提供了超时的特性。
还有几点非常重要,需要说明一下:
尽管 POSIX 信号量是计数器信号量,但是当这个计数器被设置为 1 时,它们可以提供与 Windows 事件对象相似的功能。它们并不能在等待函数中提供超时时间。如果在进行移植时,超时并不是一个影响因素,那么建议您使用 POSIX 信号量。
当与互斥一起使用时,pthreads 条件变量可以在线程之间提供基于事件的同步机制,不过这是同步的。根据应用程序的逻辑,这可以将此作为移植过程中在 Linux 上实现这种功能的一个选择。
5.jpg
创建/打开事件对象
在 Windows 中,我们使用 CreateEvent() 来创建事件对象。

HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes,
  BOOL bManualReset,
  BOOL bInitialState,
  LPCTSTR lpName
)

在这段代码中:
lpEventAttributes 是一个指针,它指向一个决定这个句柄是否能够被继承的属性。如果这个指针为 NULL,那么这个对象就不能被初始化。
bManualReset 是一个标记,如果该值为 TRUE,就会创建一个手工重置的事件,应该显式地调用 ResetEvent(),将事件对象的状态设置为无信号状态。
bInitialState 是这个事件对象的初始状态。如果该值为 true,那么这个事件对象的初始状态就被设置为有信号状态。
lpName 是指向这个事件对象名的指针。对于无名的事件对象来说,该值是 NULL。
这个函数创建一个手工重置或自动重置的事件对象,同时还要设置改对象的初始状态。这个函数返回事件对象的句柄,这样就可以在后续的调用中使用这个事件对象了。
OpenEvent() 用来打开一个现有的有名事件对象。这个函数返回该事件对象的句柄。

HANDLE OpenEvent(
  DWORD dwDesiredAccess,
  BOOL bInheritHandle,
  LPCTSTR lpName
)

在这段代码中:
dwDesiredAccess 是针对这个事件对象所请求的访问权。
bInheritHandle 是用来控制这个事件对象句柄是否可继承的标记。如果该值为 TRUE,那么这个句柄就可以被继承;否则就不能被继承。
lpName 是一个指向事件对象名的指针。
在 Linux 中,可以调用 sem_init() 来创建一个 POSIX 信号量:int sem_init(sem_t *sem, int pshared, unsigned int value)(其中 value(即信号量计数值)被设置为这个信号量的初始状态)。
Linux pthreads 使用 pthread_cond_init() 来创建一个条件变量:int pthread_cond_init(pthread_cond_t cond, pthread_condattr_t cond_attr)。
可以使用 PTHREAD_COND_INITIALIZER 常量静态地对 pthread_cond_t 类型的条件变量进行初始化,也可以使用 pthread_condattr_init() 对其进行初始化,这个函数会对与这个条件变量关联在一起的属性进行初始化。可以调用 pthread_condattr_destroy() 用来销毁属性:

int pthread_condattr_init(pthread_condattr_t *attr)
int pthread_condattr_destroy(pthread_condattr_t *attr)

等待某个事件
在 Windows 中,等待函数提供了获取同步对象的机制。我们可以使用不同类型的等待函数(此处我们只考虑 WaitForSingleObject())。这个函数会使用一个互斥对象的句柄,并一直等待,直到它变为有信号状态或超时为止。

DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD dwMilliseconds
);

在这段代码中:
hHandle 是指向互斥句柄的指针。
dwMilliseconds 是超时时间的值,单位是毫秒。如果该值为 INFINITE,那么它阻塞调用线程/进程的时间就是不确定的。
Linux POSIX 信号量使用 sem_wait() 来挂起调用线程,直到信号量的计数器变成非零的值为止。然后它会自动减小信号量计数器的值:int sem_wait(sem_t * sem)。
在 POSIX 信号量中并没有提供超时操作。这可以通过在一个循环中执行非阻塞的 sem_trywait() 来实现,该函数会对超时时间进行计数:int sem_trywait(sem_t * sem).
Linux pthreads 使用 pthread_cond_wait() 来阻塞调用线程,其时间是不确定的:int pthread_cond_wait(pthread_cond_t cond, pthread_mutex_t mutex)。在另外一方面,如果调用线程需要被阻塞一段确定的时间,那么就可以使用 pthread_cond_timedwait() 来阻塞这个线程。如果在这段指定的时间内条件变量并没有出现,那么 pthread_cond_timedwait() 就会返回一个错误:int pthread_cond_timedwait(pthread_cond_t cond, pthread_mutex_t mutex,const struct timespec *abstime)。在这里,abstime 参数指定了一个绝对时间(具体来说,就是从 1970 年 1 月 1 日 0 时 0 分 0 秒到现在所经过的时间。)
改变事件对象的状态
函数 SetEvent() 用来将事件对象的状态设置为有信号状态。对一个已经设置为有信号状态的事件对象再次执行该函数是无效的。

BOOL SetEvent(
  HANDLE hEvent
)

Linux POSIX 信号量使用 sem_post() 来发出一个事件信号量。这会唤醒在该信号量上阻塞的所有线程:int sem_post(sem_t * sem)。
调用 pthread_cond_signal() 被用在 LinuxThreads 中,以唤醒在某个条件变量上等待的一个线程,而 pthread_cond_broadcast() 用来唤醒在某个条件变量上等待的所有线程。

int pthread_cond_signal(pthread_cond_t *cond)
int pthread_cond_broadcast(pthread_cond_t *cond)

注意,条件函数并不是异步信号安全的,因此不能在信号处理函数中调用。具体地说,在信号处理函数中调用 pthread_cond_signal() 或 pthread_cond_broadcast() 可能会导致调用线程的死锁。
重置事件的状态
在 Windows 中,ResetEvent() 用来将事件对象的状态重新设置为无信号状态。

BOOL ResetEvent(
  HANDLE hEvent
);

在 Linux 中,条件变量和 POSIX 信号量都是自动重置类型的。
关闭/销毁事件对象
在 Windows 中,CloseHandle() 用来关闭或销毁事件对象。

BOOL CloseHandle(
  HANDLE hObject
);

在这段代码中,hObject 是指向同步对象句柄的指针。
在 Linux 中, sem_destroy()/ pthread_cond_destroy() 用来销毁信号量对象或条件变量,并释放它们所持有的资源:

int sem_destroy(sem_t *sem)
int pthread_cond_destroy(pthread_cond_t *cond)

有名事件对象
在 Linux 中,进程之间有名事件对象所实现的功能可以使用 System V 信号量实现。System V 信号量是计数器变量,因此可以实现 Windows 中事件对象的功能,信号量的计数器的初始值可以使用 semctl() 设置为 0。
要将某个事件的状态修改为有信号状态,可以使用 semop(),并将 sem_op 的值设置为 1。要等待某个事件,则可以使用 semop() 函数,并将 sem_op 的值设置为 -1,这样就可以阻塞调用进程,直到它变为有信号状态为止。
可以通过使用 semctl() 将信号量计数器的初始值设置为 0 来获得信号量。在使用完共享资源之后,可以使用 semop() 将信号量计数设置为 1。关于每个 System V 信号量的原型,请参阅本文中有关信号量一节的内容。
例子
下面几个例子可以帮助您理解我们在这一节中所讨论的内容。
清单 4. Windows 无名事件对象的代码

// Main thread
HANDLE hEvent; // Global Variable
// Thread 1
DWORD  dwRetCode;
// Create Event
hEvent = CreateEvent(
                     NULL,    // no security attributes
                     FALSE,   // Auto reset event
                     FALSE,   // initially set to non signaled state
                     NULL);   // un named event
// Wait for the event be signaled
dwRetCode = WaitForSingleObject(
                                hEvent,    // Mutex handle
                              INFINITE);   // Infinite wait
switch(dwRetCode) {
          case WAIT_OBJECT_O :
                 // Event is signaled
                 // go ahead and proceed the work
         default :
                   // Probe for error
}
// Completed the job,
// now close the event handle
CloseHandle(hEvent);
// Thread 2
// Condition met for the event hEvent
// now set the event
SetEvent(
         hEvent);    // Event Handle

清单 5. Linux 使用 POSIX 信号量的等效代码

// Main thread
sem_t sem     ; // Global Variable
// Thread 1
int   retCode ;
// Initialize event semaphore
retCode = sem_init(
                   sem,   // handle to the event semaphore
                   0,     // not shared
                   0);    // initially set to non signaled state
// Wait for the event be signaled
retCode = sem_wait(
                   &sem); // event semaphore handle
                          // Indefinite wait
// Event Signaled
// a head and proceed the work
// Completed the job,
// now destroy the event semaphore
retCode = sem_destroy(
                      &sem);   // Event semaphore handle
// Thread 2
// Condition met
// now signal the event semaphore
sem_post(
         &sem);    // Event semaphore Handle

清单 6. Linux 中使用条件变量的等效代码

// Main thread
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condvar = PTHREAD_COND_INITIALIZER;
// Thread 1
 ...
pthread_mutex_lock(&mutex);
// signal one thread to wake up
pthread_cond_signal(&condvar);
pthread_mutex_unlock(&mutex);
// this signal is lost as no one is waiting
// Thread 1 now tries to take the mutex lock
// to send the signal but gets blocked
     ...
    pthread_mutex_lock(&mutex);
// Thread 1 now gets the lock and can
// signal thread 2 to wake up
      pthread_cond_signal(&condvar);
      pthread_mutex_unlock(&mutex);
// Thread 2
pthread_mutex_lock(&mutex);
pthread_cond_wait(&condvar, &mutex);
pthread_mutex_unlock(&mutex);
// Thread 2 blocks indefinitely
// One way of avoiding losing the signal is as follows
// In Thread 2 - Lock the mutex early to avoid losing signal
pthread_mutex_lock (&mutex);
// Do work
.......
// This work may lead other threads to send signal to thread 2
// Thread 2 waits for indefinitely for the signal to be posted
pthread_cond_wait (&condvar, &Mutex );
// Thread 2 unblocks upon receipt of signal
pthread_mutex_unlock (&mutex);

清单 7. Windows 中使用有名事件的例子

// Process 1
DWORD  dwRetCode;
HANDLE hEvent; // Local variable
// Create Event
hEvent = CreateEvent(
                     NULL,        // no security attributes
                     FALSE,       // Auto reset event
                     FALSE,       // initially set to non signaled state
                     "myEvent");  // un named event
// Wait for the event be signaled
dwRetCode = WaitForSingleObject(
                                hEvent,    // Mutex handle
                              INFINITE);   // Infinite wait
switch(dwRetCode) {
          case WAIT_OBJECT_O :
                 // Event is signaled
                 // go ahead and proceed the work
         default :
                   // Probe for error
}
// Completed the job,
// now close the event handle
CloseHandle(hEvent);
// Process 2
HANDLE hEvent; // Local variable
// Open the Event
hEvent = CreateEvent(
                     NULL,        // no security attributes
                     FALSE,       // do not inherit handle
                     "myEvent");  // un named event
// Condition met for the event hEvent
// now set the event
SetEvent(
         hEvent);    // Event Handle
// completed the job, now close the event handle
CloseHandle(hEvent);

清单 8. Linux 中使用 System V 信号量的等效代码

// Process 1
int main()
{
    //Definition of variables
    key_t key;
    int semid;
    int Ret;
    int timeout = 0;
    struct sembuf operation[1] ;
    union semun
    {
        int val;
        struct semid_ds *buf;
        USHORT *array;
    } semctl_arg,ignored_argument;
    key = ftok(); /Generate a unique key, U can also supply a value instead
    semid = semget(key,                // a unique identifier to identify semaphore set
                     1,                // number of semaphore in the semaphore set
                     0666 | IPC_CREAT  // permissions (rwxrwxrwx) on the new
                                       //     semaphore set and creation flag
                    );
    if(semid < 0)
    {
        printf("Create semaphore set failed ");
        Exit(1);
    }
    //Set Initial value for the resource - initially not owned
    semctl_arg.val = 0; //Setting semval to 0
    semctl(semid, 0, SETVAL, semctl_arg);
    // wait on the semaphore
    // blocked until it is signaled
    operation[0].sem_op = -1;
    operation[0].sem_num = 0;
    operation[0].sem_flg = IPC_WAIT;
    ret = semop(semid, operation,1);
    // access the shared resource
    ...
    ...
    //Close semaphore
    iRc = semctl(semid, 1, IPC_RMID , ignored_argument);
}
// Process 2
int main()
{
    key_t key = KEY; //Process 2 shd know key value in order to open the
                // existing semaphore set
    struct sembuf operation[1] ;
    //Open semaphore
    semid = semget(key, 1, 0);
    // signal the semaphore by incrementing the semaphore count
    operation[0].sem_op = 1;
    operation[0].sem_num = 0;
    operation[0].sem_flg = SEM_UNDO;
    semop(semid, operation,0);
}
]]>
0 https://www.wangmin.info/recommend/win2linux-sem-event.html#comments https://www.wangmin.info/feed/recommend/win2linux-sem-event.html
将程序从windows移植到linux(进程和线程部分) https://www.wangmin.info/recommend/win2linux.html https://www.wangmin.info/recommend/win2linux.html Wed, 30 Nov 2016 14:23:00 +0800 admin 随着开发者将原本普遍的 Windows® 应用迁移到 Linux™ 平台,正在进行的向开源迁移的浪潮有可能引发极大的 移植问题。这个由三部分构成的系列文章提供一个映射指南,并附有例子,能够简化从 Windows 到 Linux 的转变。第 1 部分介绍了进程和线程。

当前,很多全球商务和服务都正在趋于开源 —— 业界的所有主要参与者都在争取实现此目标。这一趋势催生了一个重要的 迁移模式:为不同平台(Windows、OS2、Solaris 等)维持的现有产品将被移植到开放源代码的 Linux 平台。
很多应用程序在设计时并未考虑到需要将它们移植到 Linux。这有可能使移植成为一件痛苦的事情,但并非绝对如此。 本系列文章的目的是,帮助您将涉及到 IPC 和线程原语的复杂应用程序从 Windows 迁移到 Linux。我们与您分享迁移 这些关键应用程序的经验,包括要求线程同步的多线程应用程序以及要求进程间同步的多进程应用程序。
简言之,可以将此系列文章看作是一个映射文档 —— 它提供了与线程、进程和进程间通信元素(互斥体、信号量等等)相关 的各种 Windows 调用到 Linux 调用的映射。我们将那些映射分为三个部分:
第 1 部分涉及的是进程和线程。
第 2 部分处理的是信号量与事件。
第 3 部分涵盖了信号量、关键区域和等待函数。
进程
Windows 中和 Linux 中的基本执行单位是不同的。在 Windows 中,线程是基本执行单位,进程是一个容纳线程的容器。
在 Linux 中,基本执行单位是进程。Windows API 所提供的功能可以直接映射到 Linux 系统调用:
1.jpg
“类别”一列(解释了本文中所使用的分类结构)表明了 Windows 结构是否 可映射 或者 与上下文相关:
如果可映射,则 Windows 结构可以映射到特定的 Linux 结构(需要仔细检查类型、参数、返回代码等)。Windows 和 Linux 结构都提供了类似的功能。
如果是与上下文相关,则 Linux 中可能有(也可能没有)相应于给定的 Windows 结构的结构,或者 Linux 可能有不只一个提供 类似功能的结构。无论是哪种情况,都要根据应用程序上下文才能确定要使用哪个特定的 Linux 结构。
创建进程
在 Windows 中,您可以使用 CreateProcess() 来创建一个新的进程。 CreateProcess() 函数创建一个新的进程及其主线程,如下:

BOOL CreateProcess(
  LPCTSTR lpApplicationName,                  // name of executable module
  LPTSTR lpCommandLine,                      // command line string
  LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // SD
  BOOL bInheritHandles,                      // handle inheritance option
  DWORD dwCreationFlags,                     // creation flags
  LPVOID lpEnvironment,                      // new environment block
  LPCTSTR lpCurrentDirectory,                // current directory name
  LPSTARTUPINFO lpStartupInfo,               // startup information
  LPPROCESS_INFORMATION lpProcessInformation // process information
)

bInheritHandles 确定了子进程是否要继承父进程的句柄。lpApplicationName 和 lpCommandLine 给出了将要被 启动的进程的名称与路径。lpEnvironment 定义了进程可使用的环境变量。
在 Linux 中,exec* 家族函数使用一个新的进程映像取代当前进程映像(如下所示):

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int  execle(const  char  *path,  const  char  *arg  , ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);

exec 的这些版本只是内核函数 execve() (int execve(const char filename, char const argv [], char const envp[])) 的各种调用接口。在这里,argv 是包含有参数 list 的指针,envp 是包含有环境变量列表(主要是 key=value 对)的指针。
它必须与 fork() 命令一起使用,所以父进程和子进程都在运行: pid_t fork(void)。fork() 会创建 一个子进程,与父进程相比只是 PID 和 PPID 不同;实际上,资源利用设为 0。
默认情况下,exec() 继承父进程的组和用户 ID,这就使得它会依赖于父进程。可以使用 以下方法来改变:
设置指定程序文件的 set-uid 和 set-gid 位
使用 setpgid() 和 setuid() 系统调用
CreateProcessAsUser() 函数与 CreateProcess() 类似,只是 新进程是在用户通过 hToken 参数描述的安全上下文中运行。在 Linux 中,没有与此函数惟一对应的函数,但是可以使用下面的逻辑来实现对它的复制:
使用 fork() 创建一个具有新的 PID 的子进程
使用 setuid() 切换到那个新的 PID
使用 exec() 将现有进程改变为将要执行的进程
终止进程
在 Windows 中,您可以使用 TerminateProcess() 强制终止一个运行中的进程。

BOOL TerminateProcess(
  HANDLE hProcess, // handle to the process
  UINT uExitCode   // exit code for the process
);

这个函数终止运行中的进程及其相关线程。只是在非常极端的场合才会使用这个函数。
在 Linux 中,您可以使用 kill() 来强行杀死一个进程: int kill(pid_t pid, int sig)。这个系统调用会终止 id 为 PID 的进程。 您也可以使用它向任何组或者进程发出信号。
使用等待函数
在子进程依赖于父进程的情况下,您可以在父进程中使用等待函数来等待子进程的终止。在 Windows 中,您可以使用 WaitForSingleObject() 函数调用来实现此功能。
您可以使用 WaitForMultipleObject() 函数来等待多个对象。

DWORD WaitForMultipleObjects(
  DWORD nCount,             // number of handles in array
  CONST HANDLE *lpHandles,  // object-handle array
  BOOL bWaitAll,            // wait option
  DWORD dwMilliseconds      // time-out interval
);

您可以向对象句柄数组(object-handle array)中填充很多需要等待的对象。根据 bWaitALL 选项,您既可以等待所有对象被信号通知,也可以等待其中任意一个被信号通知。
在这两个函数中,如果您想等待有限的一段时间,则可以在第二个参数中指定时间间隔。如果您想无限制等待,那么使用 INFINITE 作为 dwMilliseconds 的值。将 dwMilliseconds 设置为 0 则只是检测对象的状态并返回。
在 Linux 中,如果您希望无限期等待进程被杀死,则可以使用 waitpid()。在 Linux 中,使用 waitpid() 调用无法等待限定的时间。
在这段代码中:pid_t waitpid(pid_t pid, int *status, int options),waitpid() 会无限期等待子进程的终止。在 Windows 和 Linux 中,等待函数 会挂起当前进程的执行,直到它完成等待,不过,在 Windows 中可以选择在指定的时间后退出。使用 System V 信号量,您可以实现类似于 WaitForSingleObject() 和 WaitForMultipleObject() 的限时等待或者 NO WAIT 功能,在本系列的第 2 部分中将讨论此内容。本系列的第 3 部分将深入讨论等待函数。
退出进程
退出进程指的是优雅(graceful)地退出进程,并完成适当的清除工作。在 Windows 中,您可以使用 ExitProcess() 来执行此操作。

VOID ExitProcess(
  UINT uExitCode   // exit code for all threads
);

ExitProcess() 是在进程结束处执行的方法。这个函数能够干净地停止进程。包括调用所有 链接到的动态链接库(DLL)的入口点函数,给出一个值,指出这个进程正在解除那个 DLL 的链接。
Linux 中与 ExitProcess() 相对应的是 exit():void exit(int status);。
exit() 函数会令程序正常终止,并将 &0377 状态值返回给父进程。 C 语言标准 规定了两个定义(EXIT_SUCCESS 和 EXIT_FAILURE), 可以被传递到状态参数,以说明终止成功或者不成功。
环境变量
每个进程都拥有关联到它的一组环境,其中主要是 name=value 对,指明进程可以访问的各种环境变量。尽管我们可以在 创建进程时指定环境,不过也有特定函数可以在进程创建后设置和获得环境变量。
在 Windows 中,您可以使用 GetEnvironmentVariable() 和 SetEnvironmentVariable() 来获得和设置环境变量。

DWORD GetEnvironmentVariable(
   LPCTSTR lpName,  // environment variable name
   LPTSTR lpBuffer, // buffer for variable value
   DWORD nSize      // size of buffer
);

如果成功,则此函数返回值缓存的大小,如果指定的名称并不是一个合法的环境变量名,则返回 0。 SetEnvironmentVariable() 函数为当前进程设置指定的环境变量的内容。

BOOL SetEnvironmentVariable(
  LPCTSTR lpName,  // environment variable name
  LPCTSTR lpValue  // new value for variable
);

如果函数成功,则返回值非零。如果函数失败,则返回值为零。
在 Linux 中,getenv() 和 setenv() 系统调用提供了相应的功能。

char *getenv(const char *name);
int setenv(const char *name, const char *value, int overwrite);

getenv() 函数会在环境列表中搜索与名称字符串相匹配的字符串。这个函数会返回一个 指向环境中的值的指针,或者如果不匹配则返回 NULL。setenv() 函数将变量名和值添加 到环境中,如果那个名称并不存在。如果环境中已经存在那个名称,而且如果 overwrite 非零,则它的值会被修改为 value。如果 overwrite 为零,则 name 的值不会被改变。 如果成功,则 setenv() 会返回零,如果环境中空间不足,则返回 -1。
例子
下面的例子解释了我们在本节中讨论的内容。
清单 1. Windows 进程代码

//Sample Application that explain process concepts
//Parameters Declaration/Definition
int TimetoWait;
STARTUPINFO si;
PROCESS_INFORMATION pi;
LPTSTR lpszCurrValue,LPTSTR lpszVariable;
TCHAR tchBuf[BUFSIZE];
BOOL fSuccess;
if(argc > 2)
{
    printf("InvalidArgument");
    ExitProcess(1); //Failure
}
//Get and display an  environment variable PATH
lpszCurrValue = ((GetEnvironmentVariable("PATH",tchBuf, BUFSIZE) > 0) ? tchBuf : NULL);
lpszVariable = lpszCurrValue;
//Display the environment variable
while (*lpszVariable)
    putchar(*lpszVariable++);
putchar('\n');
//Initialise si and pi
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
//Create a childProcess
if( !CreateProcess( NULL,             // No module name (use command line).
                    "SomeProcess",    // Command line.
                    NULL,             // Process handle not inheritable.
                    NULL,             // Thread handle not inheritable.
                    FALSE,            // Set handle inheritance to FALSE.
                    0,                // No creation flags.
                    NULL,             // Use parent's environment block.
                    NULL,             // Use parent's starting directory.
                    &si,              // Pointer to STARTUPINFO structure.
                    &pi )             // Pointer to PROCESS_INFORMATION structure.
                        )
{
    printf( "CreateProcess failed." );
}
// Wait until child process exits.
if(argc == 2)
{
    TIMEOUT = atoi(argv[1]);
    ret = WaitForSingleObject( pi.hProcess, TIMEOUT );
    if(ret == WAIT_TIMEOUT)
    {
        TerminateProcess(pi.hProcess);
    }
}
else
{
    WaitForSingleObject( pi.hProcess, INFINITE );
    ...
}
    ExitProcess(0); //Success

清单 2. 相应的 Linux 进程代码

#include <stdlib.h>
int main(int argc,char *argv[])
{
    //Parameters Declaration/Definition
    char PathName[255];
    char *Argptr[20];
    int rc;
    char *EnvValue,*lpszVariable;
    if(argc > 1)
    {
        printf(" Wrong parameters !!");
        exit(EXIT_FAILURE);
    }
    //Get and display an  environment variable PATH
    EnvValue = getenv("PATH");
    if(EnvValue == NULL)
    {
        printf("Invalid environment variable passed as param !!");
    }else
    {
        lpszVariable = EnvValue;
        while (*lpszVariable)
            putchar(*lpszVariable++);
        putchar('\n');
    }
    rc = fork(); //variable rc's value on success would be process ID in the parent
                 //process, and 0 in the child's thread of execution.
    switch(rc)
    {
        case -1:
            printf("Fork() function failed !!");
            ret = -1;
            break;
        case 0:
            printf("Child process...");
            setpgid(0,0);  //Change the parent grp ID to 0
        ret = execv(PathName,Argptr); // there are other flavours of exec available,
                                      // u can use any of them based on the arguments.
        if(ret == -1)
        {
            kill(getpid(),0);
        }
        break;
         default:
             // infinitely waits for child process to die
             Waitpid(rc,&status,WNOHANG);
             //Note RC will have PID returned since this is parent process.
             break;
    }
    exit(EXIT_SUCCESS);
}

2.jpg
创建线程
在 Windows 中,您可以使用 CreateThread() 来创建线程,创建的线程在调用进程的 虚拟地址空间中运行。

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,     // SD
  SIZE_T dwStackSize,                           // initial stack size
  LPTHREAD_START_ROUTINE lpStartAddress,        // thread function
  LPVOID lpParameter,                           // thread argument
  DWORD dwCreationFlags,                        // creation option
  LPDWORD lpThreadId                            // thread identifier
);

lpThreadAttributes 是指向线程属性的指针,决定了线程句柄是否能由子进程继承。
Linux 使用 pthread 库调用 pthread_create() 来派生线程:

int pthread_create (pthread_t *thread_id, pthread_attr_t *threadAttr,
                    void * (*start_address)(void *), void * arg);

注意:在 Windows 中,受可用虚拟内存的限制,一个进程可以创建的线程数目是有限的。默认情况下, 每个线程有一兆栈空间。因此,您最多可以创建 2,028 个线程。如果您减小默认栈大小,那么可以创建更多线程。 在 Linux 中,使用 ULIMIT -a(limits for all users)可以获得每个用户可以创建的线程 的最大数目,可以使用 ULIMIT -u 来修改它,不过只有在登录时才可以这样做。 /usr/Include/limit.h 和 ulimit.h 下的头文件定义了这些内容。您可以修改它们并重新编译内核,以使其永久生效。 对于 POSIX 线程限制而言,local_lim.h 中定义的 THREAD_THREADS_MAX 宏定义了数目的上限。
指定线程函数
CreateThread() 中的 lpStartAddress 参数是刚 创建的线程要执行的函数的地址。
pthread_create() 库调用的 start_address 参数是 刚创建的线程要执行的函数的地址。
传递给线程函数的参数
在 Windows 中,系统调用 CreateThread() 的参数 lpParameter 指定了要传递给刚创建的线程的参数。它指明了将要传递给新线程的数据条目的地址。
在 Linux 中,库调用 pthread_create() 的参数 arg 指定了将要传递给新线程的参数。
设置栈大小
在 Windows 中,CreateThread() 的参数 dwStackSize 是将要分配给新 线程的以字节为单位的栈大小。栈大小应该是 4 KB 的非零整数倍,最小为 8 KB。
在 Linux 中,栈大小在线程属性对象中设置;也就是说,将类型为 pthread_attr_t 的 参数 threadAttr 传递给库调用 pthread_create()。 在设置任何属性之前,需要通过调用 pthread_attr_init() 来初始化这个对象。 使用调用 pthread_attr_destroy() 来销毁属性对象:

int pthread_attr_init(pthread_attr_t *threadAttr);
int pthread_attr_destroy(pthread_attr_t *threadAttr);

注意,所有 pthread_attr_setxxxx 调用都有与 pthread_xxxx 调用(如果有)类似的功能,只是您只能在线程创建之前使用 pthread_attr_xxxx,来更新将 要作为参数传递给 pthread_create 的属性对象。同时,您在创建线程之后的任意时候都可以使用 pthread_xxxx。
使用调用 pthread_attr_setstacksize() 来设置栈大小: int pthread_attr_setstacksize(pthread_attr_t *threadAttr, int stack_size);。
退出线程
在 Windows 中,系统调用 ExitThread() 会终止线程。 dwExitCode 是线程的返回值,另一个线程通过调用 GetExitCodeThread() 就可以得到它。

VOID ExitThread(
  DWORD dwExitCode   // exit code for this thread
);

Linux 中与此相对应的是库调用 pthread_exit()。 retval 是线程的返回值,可以在另一个线程中通过调用 pthread_join() 来获得它: int pthread_exit(void* retval);。
线程状态
在 Windows 中,没有保持关于线程终止的显式线程状态。不过,WaitForSingleObject() 让线程能够显式地等待进程中某个指定的或者非指定的线程终止。
在 Linux 中,默认以可连接(joinable)的状态创建线程。在可连接状态中,另一个线程可以同步这个线程的终止, 使用函数 pthread_join() 来重新获得其终止代码。可连接的线程只有在被连接后 才释放线程资源。
Windows 使用 WaitForSingleObject() 来等待某个线程终止:

DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD dwMilliseconds
);

其中:
hHandle 是指向线程句柄的指针。
dwMilliseconds 是以毫秒为单位的超时值。 如果这个值被设置为 INFINITE,则它会无限期地阻塞进行调用的线程/进程。
Linux 使用 pthread_join() 来完成同样的功能: int pthread_join(pthread_t thread, void *thread_return);。
在分离的状态中,线程终止后线程资源会立即被释放。通过对线程属性对象调用 pthread_attr_setdetachstate() 可以设置分离状态: int pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate);。 以可连接状态创建的线程,稍后可以被转为分离状态,方法是使用 pthread_detach() 调用:int pthread_detach (pthread_t id);。
改变优先级
在 Windows 中,线程的优先级由其进程的优先级等级以及进程优先级等级中的线程优先级层次决定。 在 Linux 中,线程本身就是一个执行单位,有其自己的优先级。它与其进程的优先级没有依赖关系。
在 Windows 中,您可以使用 SetPriorityClass() 来设置特定进程的优先级等级:

BOOL SetPriorityClass(
  HANDLE hProcess,         // handle to the process
  DWORD dwPriorityClass    // Priority class
);

dwPriorityClass 是进程的优先级等级,它可以设置为下列值中的任意一个:
IDLE_PRIORITY_CLASS
BELOW_NORMAL_PRIORITY_CLASS
NORMAL_PRIORITY_CLASS
ABOVE_NORMAL_PRIORITY_CLASS
HIGH_PRIORITY_CLASS
REALTIME_PRIORITY_CLASS
一旦设置了进程的优先级等级,就可以使用 SetThreadPriority() 在进程的 优先级等级内部设置线程的优先级层次:

BOOL SetThreadPriority(
  HANDLE hThread,
  int nPriority
);

nPriority 是线程的优先级值,它被设置为下列之一;
THREAD_PRIORITY_ABOVE_NORMAL 将优先级设置为比优先级等级高 1 级。
THREAD_PRIORITY_BELOW_NORMAL 将优先级设置为比优先级等级低 1 级。
THREAD_PRIORITY_HIGHEST 将优先级设置为比优先级等级高 2 级。
THREAD_PRIORITY_IDLE 为 IDLE_PRIORITY_CLASS、BELOW_NORMAL_PRIORITY_CLASS、NORMAL_PRIORITY_CLASS、ABOVE_NORMAL_PRIORITY_CLASS 或 HIGH_PRIORITY_CLASS 进程将基优先级设置 1,为 REALTIME_PRIORITY_CLASS 进程将基优先级设置为 16。
THREAD_PRIORITY_LOWEST 将优先级设置为比优先级等级低 2 级。
THREAD_PRIORITY_NORMAL 为优先级等级设置为普通优先级。
THREAD_PRIORITY_TIME_CRITICAL 为 IDLE_PRIORITY_CLASS、BELOW_NORMAL_PRIORITY_CLASS、NORMAL_PRIORITY_CLASS、ABOVE_NORMAL_PRIORITY_CLASS 或 HIGH_PRIORITY_CLASS 进程将基优先级设置 15,为 REALTIME_PRIORITY_CLASS 进程将基优先级设置为 31。

进程和线程的例子
为了结束这一期文章,让我们来看下面类型的进程和线程的一些例子:
普通的或者常规的进程和线程
对时间要求严格的(time-critical)或者实时的进程和线程
普通的或常规的进程/线程
使用 Linux 系统调用 setpriority() 来设置或者修改普通进程和线程的优先级 层次。参数的范围是 PRIO_PROCESS。将 id 设置为 0 来修改当前进程(或线程)的优先级。 此外,delta 是优先级的值 —— 这一次是从 -20 到 20。另外,要注意在 Linux 中较低的 delta 值代表较高的优先级。 所以,使用 +20 设置 IDLETIME 优先级,使用 0 设置 REGULAR 优先级。
在 Windows 中,常规线程的优先级的范围是从 1(较低的优先级)到 15(较高的优先级)。不过,在 Linux 中,普通 非实时进程的优先级范围是从 -20(较高的)到 +20(较低的)。在使用之前必须对此进行映射: int setpriority(int scope, int id, int delta);。
对时间要求严格的和实时的进程和线程
您可以使用 Linux 系统调用 sched_setscheduler() 来修改正在运行的进程的调度优先级: int sched_setscheduler(pit_t pid, int policy, const struct sched_param *param);。
参数 policy 是调度策略。policy 的可能的值是 SCHED_OTHER (常规的非实时调度)、SCHED_RR(实时 round-robin 策略)和 SCHED_FIFO(实时 FIFO 策略)。
在此,param 是指向描述调度优先级结构体的指针。它的范围是 1 到 99,只用于 实时策略。对于其他的(普通的非实时进程),它为零。
在 Linux 中,作为一个大家所熟知的调度策略,也可以通过使用系统调用 sched_setparam 来仅修改进程优先级: int sched_setparam(pit_t pid, const struct sched_param *param);。
LinuxThreads 库调用 pthread_setschedparam 是 sched_setscheduler 的线程版本,用于动态修改运行着的线程的调度优先级和策略: int pthread_setschedparam(pthread_t target_thread, int policy, const struct sched_param *param);。
参数 target_thread 告知线程要修改谁的优先级;param 指定了优先级。
LinuxThreads 库会调用 pthread_attr_setschedpolicy,并且您可以在线程被创建之前 使用 pthread_attr_setschedparam 来设置线程属性对象的调度策略和优先级层次:

int pthread_attr_setschedpolicy(pthread attr_t *threadAttr, int policy);
int pthread_attr_setschedparam(pthread attr_t *threadAttr, const struct sched_param *param);

在 Windows 中,实时线程的优先级范围是从 16(较低的优先级)到 31(较高的优先级)。在 Linux 中, 实时线程的优先级范围是从 99(较高的)到 1(较低的优先级)。在使用前必须对此进行映射。
例子
下面的清单阐述了本节中的概念。
清单 3. Windows 线程示例

Main Thread
enum stackSize = 120 * 1024 ;
// create a thread normal and real time thread
DWORD  normalTId, realTID;
HANDLE normalTHandle, realTHandle;
normalTHandle = CreateThread(
                NULL,            // default security attributes
                stackSize,       // 120K
                NormalThread,    // thread function
                NULL,            // argument to thread function
                0,               // use default creation flags
                &normalTId);     // returns the thread identifier
// Set the priority class as "High priority"
SetPriorityClass(pHandle, HIGH_PRIORITY_CLASS);
normalTHandle = CreateThread(
                 NULL,            // default security attributes
                 stackSize,       // 120K
                 NormalThread,    // thread function
                 NULL,            // argument to thread function
                 0,               // use default creation flags
                &normalTId);     // returns the thread identifier
CloseHandle(threadHandle);
...
...
// Thread function
DWORD WINAPI NormalThread ( LPVOID lpParam )
{
    HANDLE tHandle,pHandle;
    pHandle = GetCurrentProcess();
    tHandle = GetCurrentThread();
    // Set the priority class as "High priority"
    SetPriorityClass(pHandle, HIGH_PRIORITY_CLASS);
    // increase the priority by 2 points above the priority class
    SetThreadPriority(tHandle,THREAD_PRIORITY_HIGHEST);
    // perform job at high priority
    ...
    ...
    ...
    // Reset the priority class as "Normal"
   SetPriorityClass(pHandle, NORMAL_PRIORITY_CLASS);
    // set the priority back to normal
    SetThreadPriority(tHandle,THREAD_PRIORITY_NORMAL);
    // Exit thread
    ExitThread(0);
}
// Thread function
DWORD WINAPI RealTimeThread ( LPVOID lpParam )
{
    HANDLE tHandle, pHandle ;
    pHandle = GetCurrentProcess();
    tHandle = GetCurrentThread  ();
    // Set the priority class as "Real time"
   SetPriorityClass(pHandle, REALTIME_PRIORITY_CLASS);
    // increase the priority by 2 points above the priority class
    SetThreadPriority(tHandle,THREAD_PRIORITY_HIGHEST);
    // do time critical work
    ...
    ...
    ...
    // Reset the priority class as "Normal"
   SetPriorityClass(pHandle, NORMAL_PRIORITY_CLASS);
    // Reset the priority back to normal
    SetThreadPriority(tHandle,THREAD_PRIORITY_NORMAL);
    ExitThread(0);
}

清单 4. Linux 相应的线程代码

static void * RegularThread (void *);
static void * CriticalThread (void *);
// Main Thread
       pthread_t thread1, thread2;  // thread identifiers
       pthread_attr_t threadAttr;
       struct sched_param param;  // scheduling priority
       // initialize the thread attribute
       pthread_attr_init(&threadAttr);
       // Set the stack size of the thread
       pthread_attr_setstacksize(&threadAttr, 120*1024);
       // Set thread to detached state. No need for pthread_join
       pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
       // Create the threads
       pthread_create(&thread1, &threadAttr, RegularThread, NULL);
       pthread_create(&thread2, &threadAttr, CriticalThread,NULL);
       // Destroy the thread attributes
       pthread_attr_destroy(&threadAttr);
       ...
       ...
  // Regular non-realtime Thread function
  static void * RegularThread (void *d)   {
       int priority = -18;
       // Increase the priority
       setpriority(PRIO_PROCESS, 0, priority);
       // perform high priority job
       ...
       ...
       // set the priority back to normal
       setpriority(PRIO_PROCESS, 0, 0);
       pthread_exit(NULL);
   }
   // Time Critical Realtime Thread function
   static void * CriticalThread (void *d) {
       // Increase the priority
        struct sched_param param;  // scheduling priority
        int policy = SCHED_RR;     // scheduling policy
        // Get the current thread id
        pthread_t thread_id = pthread_self();
        // To set the scheduling priority of the thread
        param.sched_priority = 90;
        pthread_setschedparam(thread_id, policy, &param);
        // Perform time critical task
        ...
        ...
        // set the priority back to normal
        param.sched_priority = 0;
        policy = 0;             // for normal threads
        pthread_setschedparam(thread_id, policy, &param);
        ....
        ....
        pthread_exit(NULL);
   }
]]>
0 https://www.wangmin.info/recommend/win2linux.html#comments https://www.wangmin.info/feed/recommend/win2linux.html
qt翻译国际化 https://www.wangmin.info/recommend/qt_translation.html https://www.wangmin.info/recommend/qt_translation.html Tue, 18 Oct 2016 12:42:00 +0800 admin 一、简单一个例子,比如下面代码,使用tr()来控制需要翻译的代码
void MainWindow::on_Test_clicked()
{

QString a = tr("Do a test.");
qDebug() << a;
Dialog * aa = new Dialog();
aa->show();

}
二、对tr里面的内容进行翻译和发布
1、使用lupdate命令和lrelease命令进行转化
2、使用QT Creator进行可视化操作
update.jpg
如果使用第二种办法的话还需要更改.pro文件,增加以下代码
TRANSLATIONS = zh_cn.ts
对生成的ts文件进行修改,内容是xml格式的,文本编辑器进行更改就可以,确认无误后就把translation里面的type标签去掉,然后就可以进行发布。
三、进行发布
修改main.cpp,大概结构如下,有两个需要注意的地方
int main(int argc, char *argv[])
{

QApplication a(argc, argv);

QTranslator tsor;           //创建翻译器
/*
 * 加载语言包,注意:
 * a.如果是在IDE中调试的话就要把qm文件放到Makefie的同级目录
 * b.如果是直接运行exe文件的话就要把qm文件放到exe的同级目录
 */
bool ret = tsor.load("zh_cn.qm");
qDebug() << ret;
a.installTranslator(&tsor); //安装翻译器

MainWindow w;
w.show();

return a.exec();

}

]]>
0 https://www.wangmin.info/recommend/qt_translation.html#comments https://www.wangmin.info/feed/recommend/qt_translation.html
rhel 7使用unbound部署ddns https://www.wangmin.info/recommend/unbound_ddns.html https://www.wangmin.info/recommend/unbound_ddns.html Thu, 13 Oct 2016 14:39:00 +0800 admin 1、首先第一步安装,我这里已经安装过了
[root@colourstek wangmin]# yum install unbound
Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Package unbound-1.4.20-26.el7.x86_64 already installed and latest version
Nothing to do
[root@colourstek wangmin]# systemctl restart unbound //启动DNS服务
[root@colourstek wangmin]# systemctl enable unbound //开机自动启动DNS服务
ln -s ‘/usr/lib/systemd/system/unbound.service‘ ‘/etc/systemd/system/multi-user.target.wants/unbound.service‘

2、修改配置文件
unbound安装好之后,默认配置文件地址为/etc/unbound/unbound.conf
贴上我的配置文件,加粗部分为我的修改
dns1.jpg
dns2.jpg
dns3.jpg
dns4.jpg
dns5.jpg
dns6.jpg
dns7.jpg
dns8.jpg
3、验证
[root@colourstek wangmin]# unbound-checkconf
[1476341835] unbound-checkconf[176447:0] warning: root hints /etc/unbound/root.hints: no NS content
unbound-checkconf: no errors in /etc/unbound/unbound.conf

4、重启unbound服务,如果防火墙是开的最好关掉
[root@colourstek wangmin]# systemctl restart unbound

]]>
0 https://www.wangmin.info/recommend/unbound_ddns.html#comments https://www.wangmin.info/feed/recommend/unbound_ddns.html
Linux下的scp命令用法详解 https://www.wangmin.info/unix/linux-how-to-use-scp-commond.html https://www.wangmin.info/unix/linux-how-to-use-scp-commond.html Fri, 22 Feb 2013 15:54:00 +0800 admin 常用用法举例:

1、复制远程服务器的文件到本地:
scp root@120.18.50.33:/data/a.gz /home/
2、复制远程服务器的目录到本地:
scp -vrp root@120.18.50.33:/data/a/ /home/
3、复制本地的文件到远程服务器:
scp /home/a.gz root@120.18.50.33:/data/
4、复制本地的目录到远程服务器:
scp -vrp /home/ root@120.18.50.33:/data/

SCP 命令语法
scp [-1245BCpqrv] [-c cipher] [F ssh_config] [-I identity_file] [-l limit] [-o ssh_option] [-P port] [-S program] [[user@]host1:] file1 […] [[suer@]host2:]file2

SCP 命令说明
Scp在主机间复制文件。他使用 ssh(1)作为数据传输。而且用同样认证和安全性。 scp将在认证中请求输入密码所有的文件可能需要服务器和用户的特别描述来指明文件将被复制到/从某台服务器。两个远程登录的服务器间的文件复制是允许的。

SCP 命令选项
-1 强制scp 用协议1
-2 强制scp 用协议2
-4 强制scp用IPV4的网址
-6 强制scp用IPV6的网址
-B 选择批处理模式(防止输入密码)
-C 允许压缩。 标注-C到ssh(1)来允许压缩
-c cipher
选择cipher来加密数据传输。这个选项直接传递到ssh(1)
-F ssh_config
设定一个可变动的用户配置给ssh.这个选项直接会被传递到ssh(1)
-i identity_file
选择被RSA认证读取私有密码的文件。这个选项可以直接被传递到ssh(1)
-l limit
限制传输带宽,也就是速度 用Kbit/s的速度
-o ssh_option
可以把ssh_config中的配置格式传到ssh中。这种模式对于说明没有独立的scp文件中断符的scp很有帮助。关于选项的如下。而他们的值请参看ssh_config(5)
-P port
指定连接远程连接端口。注意这个选项需要写成大写的模式。因为-p已经早保留了次数和模式
-S program
指定一个加密程序。这个程序必须可读所有ssh(1)的选项。
-p 指定修改次数,连接次数,还有对于原文件的模式
-q 把进度参数关掉
-r 递归的复制整个文件夹
-S program
指定一个加密程序。这个程序必须可读所有ssh(1)的选项。
-V 冗余模式。 让 scp 和 ssh(1) 打印他们的排错信息, 这个在排错连接,认证,和配置中非常有用。

SCP 命令诊断
scp 返回0 成功时,不成功时返回值大于0

SCP 命令不需要输入用户密码的使用方法

在两台机器的两个用户之间建立安全的信任关系后,可实现执行scp命令时不需要输入用户密码。

  1. 在机器A上root用户执行 ssh-keygen 命令,生成建立安全信任关系的证书。

[root@A root]# ssh-keygen -b 1024 -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): <– 直接输入回车
Enter passphrase (empty for no passphrase): <– 直接输入回车
Enter same passphrase again: <– 直接输入回车
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is: ……

注意:在程序提示输入 passphrase 时直接输入回车,表示无证书密码。
上述命令将生成私钥证书 id_rsa 和公钥证书 id_rsa.pub,存放在用户目录的 .ssh 子目录中。

  1. 将公钥证书 id_rsa.pub 复制到机器B的root目录的.ssh子目录中,同时将文件名更换为authorized_keys。

[root@A root]# scp -p .ssh/id_rsa.pub root@机器B的IP:/root/.ssh/authorized_keys
root@192.168.3.206’s password: <– 输入机器B的root用户密码

在执行上述命令时,两台机器的root用户之间还未建立安全信任关系,所以还需要输入机器B的root用户密码。
经过以上2步,就在机器A的root和机器B的root之间建立安全信任关系。下面我们看看效果:

[root@A root]# scp -p test root@机器B的IP地址:/root

成功后就真的不再需要输入密码了。

]]>
0 https://www.wangmin.info/unix/linux-how-to-use-scp-commond.html#comments https://www.wangmin.info/feed/unix/linux-how-to-use-scp-commond.html
firefox的预处理问题(400 Bad Request) https://www.wangmin.info/network/firefx-bad-request-syn.html https://www.wangmin.info/network/firefx-bad-request-syn.html Mon, 28 Jan 2013 16:04:00 +0800 admin 今天发现了一个很奇怪的bug,调试的时候发现是由firefox 18浏览器中的预处理出现了一点问题。
首先看一下问题:
通过抓包发现如下图所示:
<img class="alignleft size-full wp-image-490" alt="11" src="http://www.makefile.net/wp-content/uploads/2013/01/11.jpg"; width="1280" height="800" />
首先看一下337的这一条数据包。它是一个TCP数据包,是TCP建立连接三次握手中的第一步SYN包,当我查看具体的数据包的时候感觉特么的奇怪。如下图所示:
<img src="http://www.makefile.net/wp-content/uploads/2013/01/22.jpg"; alt="22" width="1280" height="800" class="alignleft size-full wp-image-491" />
竟然是400 Bad Request的请求包,可是在HTTP的服务端打印出来的时候也很奇怪,是空的请求。
其实解决办法也很简单,就是如果是空请求报直接reset掉它,不知道算不算firefox的一个bug.

]]>
0 https://www.wangmin.info/network/firefx-bad-request-syn.html#comments https://www.wangmin.info/feed/network/firefx-bad-request-syn.html