东东东 陈煜东的博客

标签存档: Linux ( 1 / 2)

Python Subprocess Popen 管道阻塞问题分析解决

使用Subprocess Popen的类库困挠了我一个月的问题终于解决了。

一句话就是:等待命令返回不要使用wait(),而是使用communicate(),但注意内存,大输出使用文件。

错误的使用例子

之前的代码这样使用的。

# 不合适的代码
def run_it(self, cmd):
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True,
                         stderr=subprocess.PIPE, close_fds=True)
    log.debug('running:%s' % cmd)
    p.wait()
    if p.returncode != 0:
        log.critical("Non zero exit code:%s executing: %s" % (p.returncode, cmd))
    return p.stdout

这段代码之前用着一直没有问题的,后来不知道为何就不能用了(后面知道了,原来输出内容增加,输出的问题本太长,把管道给堵塞了)。

这样的代码也在之前的一个项目中使用,而且调用的次数有上亿次,也没什么问题。之前倒是也卡住了一次,不过有个大神把问题找到了,因为Python版本低于2.7.6,Python对close_fds的一些实现不太好导致的,没有把管道释放掉,一直卡住。设置close_fds=True。不过这个并没有解决我的问题。

解决了我的问题

当时想着既然卡住了,那我就看看是输出了什么才卡住的,结果现有的代码无法支持我的想法,就换了代码,没想到就不卡住了。

def run_it(cmd):
    # _PIPE = subprocess.PIPE
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True,
                         stderr=subprocess.PIPE) #, close_fds=True)

    log.debug('running:%s' % cmd)
    out, err = p.communicate()
    log.debg(out)
    if p.returncode != 0:
        log.critical("Non zero exit code:%s executing: %s" % (p.returncode, cmd))
    return p.stdout

看看Python文档信息

Warning

Use communicate() rather than .stdin.write, .stdout.read or .stderr.read to avoid deadlocks due to any of the other OS pipe buffers filling up and blocking the child process.

Popen.wait()
    Wait for child process to terminate. Set and return returncode attribute.

    Warning This will deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.
Popen.communicate(input=None)
    Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child.

    communicate() returns a tuple (stdoutdata, stderrdata).

    Note that if you want to send data to the process’s stdin, you need to create the Popen object with stdin=PIPE. Similarly, to get anything other than None in the result tuple, you need to give stdout=PIPE and/or stderr=PIPE too.

    Note The data read is buffered in memory, so do not use this method if the data size is large or unlimited.

之前没注意,再细看一下文档,感觉豁然开朗。

Linux管道限制,为什么会阻塞呢?

下面来看看Can someone explain pipe buffer deadlock?的回答。

子进程产生一些数据,他们会被buffer起来,当buffer满了,会写到子进程的标准输出和标准错误输出,这些东西通过管道发送给父进程。当管道满了之后,子进程就停止写入,于是就卡住了。

及时取走管道的输出也没有问题

# 及时从管道中取走数据
def run_it(self, cmd):
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True,
                         stderr=subprocess.PIPE, close_fds=True)
    log.debug('running:%s' % cmd)
    for line in iter(p.stdout.readline, b''):
        print line,          # print to stdout immediately
    p.stdout.close()
    p.wait()
    if p.returncode != 0:
        log.critical("Non zero exit code:%s executing: %s" % (p.returncode, cmd))
    return p.stdout

看了Python的communicate()内部就是将stdout/stderr读取出来到一个list变量中的,最后函数结束时返回。

测试Linux管道阻塞问题

看到别人的例子,一直在想怎么测试输出64K的数据,发现dd这个思路很棒,是见过最优雅的例子了,精确控制输出的长度,其他都是从某些地方搞来大文件导入进来。

#!/usr/bin/env python
# coding: utf-8
# yc@2013/04/28

import subprocess

def test(size):
    print 'start'

    cmd = 'dd if=/dev/urandom bs=1 count=%d 2>/dev/null' % size
    p = subprocess.Popen(args=cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
    #p.communicate()
    p.wait()  # 这里超出管道限制,将会卡住子进程

    print 'end'

# 64KB
test(64 * 1024)

# 64KB + 1B
test(64 * 1024 + 1)

# output :
start
end
start   #  然后就阻塞了。

首先测试输出为 64KB 大小的情况。使用 dd 产生了正好 64KB 的标准输出,由 subprocess.Popen 调用,然后使用 wait() 等待 dd 调用结束。可以看到正确的 start 和 end 输出;然后测试比 64KB 多的情况,这种情况下只输出了 start,也就是说程序执行卡在了 p.wait() 上,程序死锁。

总结

那死锁问题如何避免呢?官方文档里推荐使用 Popen.communicate()。这个方法会把输出放在内存,而不是管道里,所以这时候上限就和内存大小有关了,一般不会有问题。而且如果要获得程序返回值,可以在调用 Popen.communicate() 之后取 Popen.returncode 的值。

但真的如果超过内存了,那么要考虑比如文件 stdout=open("process.out", "w") 的方式来解决了,不能使用管道了。

另外说一下。管道的要用清楚,不要随意的乱世用管道。比如没有input的时候,那么stdin就不要用管道了。

还有不要把简单的事情复杂化。比如echo 1 > /sys/linux/xxx修改文件,这么简单的功能就不要用Linux的shell调用了,使用Python自带的 open('file', 'w').write('1') 。尽量保持Python范。

参考

分类: Python

ssh密钥登录失败

搞一个ssh的密钥登录,结果发现就是无法使用密钥登录,非让我输入密码。苦恼。

输入ssh连接代码

ssh -i private.key -v user@host.com -p22

从连接的信息中看不出有什么问题。

debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password
debug1: Next authentication method: publickey
debug1: Offering public key: private.key
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password
debug1: Next authentication method: password

已经提示说了,使用公钥登录,并且提供了私钥,但是还是提示让我输入密码。

但是我使用另外一个帐号去登录,发现是ok的,可以登录成功。我把成功的那个authorized_keys复制到我的那个用户名下,发现还是不能登录。但是验证了服务器的sshd功能是正常运行的,否则另外一个账户就没办法登录了。我觉得两个用户名的所在的环境应该是相同了,但是确实无法登录。

想到了客户端这里的连接没有更多有效的信息,那就想到了去服务器上看看相关的信息。vim /var/log/secure查看一下日志。发现有这么一段话:

Authentication refused: bad ownership or modes for directory /home/user/.ssh

上网搜了一下这个问题,发现原来是.ssh的目录权限不对,设置一下正确的权限:

chmod 700 ~/.ssh

在此过程中还学习到了一个sshd的测试模式。

 /usr/sbin/sshd -p 10022 -d
      -d     以调试模式运行。服务器将在前台运行并发送非常详细的调试日志信息,
             服务器将只允许接入一个连接,并且不派生出子进程。仅用于调试目的。
             使用多个 -d 选项可以输出更详细的调试信息(最多3个)。

会开启一个sshd的调试模式,新建一个10022端口,在客户端连接这个端口的时候,服务器端会有debug日志输出在屏幕上,这个时候就可以查看详细的信息。然后再针对信息进行解决。

总结

服务器用户对于ssh目录权限有一些权限要求,权限不对的话ssh无法工作,建议以下权限作为最小的权限。

chmod 700 .ssh          # chmod 755 .ssh 也是可以的
chmod 600 .ssh/authorized_keys
chmod 400 .ssh/private.key  #把密钥的权限也设置为最小

终于又可以愉快的编程了。

分类: Linux

Linux ntpdate同步网络时间

自己的Linux服务器的时间和PC机上的时间不太对,打log的时间对不上,不太方便调式信息的判断,因此需要同步一下Linux服务器的时间和自己Windows的时间,两者一致,才方便调式的查看呢。

同步网络时间

在Linux下,我们可以使用ntpdate进行网络时间的同步,而不是我们自己去设置时间。这个命令的使用很简单,

ntpdate  0.cn.pool.ntp.org

另外网络时间同步和时区是不一样的。你可以选择任何一台网络时间同步服务器来同步你的时间,只要你的时区设置是对的,那么你的Linux上的时间就是对的。因为全球都是基于一个标准时间来约定的,美国人民与我们不同的是时区不同,经过换算,我们和他们的标准时间是一样的。

定时的同步时间

我们可以使用crontab来定时的同步时间

vim /etc/crontab
10 5 * * * root (/usr/sbin/ntpdate 0.cn.pool.ntp.org && /sbin/hwclock -w) &> /var/log/ntpdate.log 

每天的5点10分crontab运行一次命令,自动同步时间。

如果你具有多台的服务器,不要使用这个方法来定时的同步的你服务器,请使用ntpd来进行,这个还可以校准始终的问题。详情查看鸟哥

使用ntpdata造成的时间的越变还可能引发因某些依赖连续时间的程序的问题。一般第一次使用ntpdate,接下来使用ntpd服务来不断的调整时间。参见http://blog.sina.com.cn/s/blog_3f3422fd0100f06c.html

如何设置时区

将时区设置为东8区的时间,虽然服务器在全球的不同地方,但是我们人在中国,看着中国的时间比较有感觉。

cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
date
# Mon Mar 31 11:02:55 CST 2014

另外如果使用date命令查看时间,发现刚刚好相差8个小时或者其他的小时,那么应该就是你的时区设置不对,快快修改一下吧。

网络时间同步服务器列表

全球那么多的网络时间同步器,那么使用哪个好呢。我们知道数据在网络上流动是由延迟的,因此我们选择离我们服务器越近的服务器进行同步,时间越准。

时间服务器分为两种,一种是一级时间服务器,另外一种是二级时间服务器。我们如果是同步自己的服务器的时间,那么选择二级时间服务器,因为一级时间服务器是为二级时间服务器提供时间校对服务器,我们尽量不要增加一级服务器的压力。这种层级的概念和DNS的层级概念是一致的。

一级时间服务器列表:http://support.ntp.org/bin/view/Servers/StratumOneTimeServers

二级时间服务器列表:http://support.ntp.org/bin/view/Servers/StratumTwoTimeServers

附二级服务器列表:

  • 0.pool.ntp.org  有域名负载均衡
  • 0.cn.pool.ntp.org  有域名负载均衡
  • ntp.tuna.tsinghua.edu.cn 清华大学
  • time.windows.com    微软

分类: Linux

[转]Linux epoll给我们带来什么

Q:网络服务器的瓶颈在哪? A:IO效率。

在大家苦苦的为在线人数的增长而导致的系统资源吃紧上的问题正在发愁的时候,Linux 2.6内核中提供的System Epoll为我们提供了一套完美的解决方案。传统的select以及poll的效率会因为在线人数的线形递增而导致呈二次乃至三次方的下降,这些直接导致了网络服务器可以支持的人数有了个比较明显的限制。

自从Linux提供了/dev/epoll的设备以及后来2.6内核中对/dev/epoll设备的访问的封装(System Epoll)之后,这种现象得到了大大的缓解,如果说几个月前,大家还对epoll不熟悉,那么现在来说的话,epoll的应用已经得到了大范围的普及。

那么究竟如何来使用epoll呢?其实非常简单。 通过在包含一个头文件#include <sys/epoll.h>以及几个简单的API将可以大大的提高你的网络服务器的支持人数。

首先通过create_epoll(int maxfds)来创建一个epoll的句柄,其中maxfds为你epoll所支持的最大句柄数。这个函数会返回一个新的epoll句柄,之后的所有操作将通过这个句柄来进行操作。在用完之后,记得用close()来关闭这个创建出来的epoll句柄。

之后在你的网络主循环里面,每一帧的调用epoll_wait(int epfd, epoll_event events, int max events, int timeout)来查询所有的网络接口,看哪一个可以读,哪一个可以写了。基本的语法为:

nfds = epoll_wait(kdpfd, events, maxevents, -1);

其中kdpfd为用epoll_create创建之后的句柄,events是一个epoll_event*的指针,当epoll_wait这个函数操作成功之后,epoll_events里面将储存所有的读写事件。max_events是当前需要监听的所有socket句柄数。最后一个timeout是epoll_wait的超时,为0的时候表示马上返回,为-1的时候表示一直等下去,直到有事件范围,为任意正整数的时候表示等这么长的时间,如果一直没有事件,则范围。一般如果网络主循环是单独的线程的话,可以用-1来等,这样可以保证一些效率,如果是和主逻辑在同一个线程的话,则可以用0来保证主循环的效率。

epoll_wait范围之后应该是一个循环,遍利所有的事件:

for(n = 0; n < nfds; ++n) {
    if(events[n].data.fd == listener) { //如果是主socket的事件的话,则表示有新连接进入了,进行新连接的处理。
        client = accept(listener, (struct sockaddr *) &local, &addrlen);
    if(client < 0){
        perror("accept");
        continue;
    }
    setnonblocking(client); // 将新连接置于非阻塞模式
    ev.events = EPOLLIN | EPOLLET; // 并且将新连接也加入EPOLL的监听队列。

注意,这里的参数EPOLLIN | EPOLLET并没有设置对写socket的监听,如果有写操作的话,这个时候epoll是不会返回事件的,如果要对写操作也监听的话,应该是EPOLLIN | EPOLLOUT | EPOLLET

ev.data.fd = client;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) {
  // 设置好event之后,将这个新的event通过epoll_ctl加入到epoll的监听队列里面,这里用EPOLL_CTL_ADD来加一个新的epoll事件,
  //通过EPOLL_CTL_DEL来减少一个epoll事件,通过EPOLL_CTL_MOD来改变一个事件的监听方式。
    fprintf(stderr, "epoll set insertion error: fd=%d0, client);
    return -1;

} else {  // 如果不是主socket的事件的话,则代表是一个用户socket的事件,
         //则来处理这个用户socket的事情,比如说read(fd,xxx)之类的,或者一些其他的处理。
    do_use_fd(events[n].data.fd);
}

对,epoll的操作就这么简单,总共不过4个API:epoll_create, epoll_ctl, epoll_wait和close。 如果您对epoll的效率还不太了解,请参考我之前关于网络游戏的网络编程等相关的文章。

本文转载自:http://dev.gameres.com/Program/Control/Epoll.htm

分类: 网络

使用libvirt和qemu将pci pass through设备添加到虚拟机上

透传的优势

guest使用透传设备可以获得设备近乎原生的性能,

PCI pass-throught设备给动态迁移带来的问题, dest host可能没有同样的硬件.

就算可以模拟一个设备,但是原始设备的内部状态不能获得.

VT-d support

In order to assign devices in KVM, you’ll need a system which supports VT-d. This has nothing to do with the VT-x support of your CPU, VT-d needs to be supported by both your chipset on your motherboard and by your CPU.

If you are in doubt whether your motherboard or CPU supports VT-d or not, the Xen VT-d wikipage has some pointers of VT-d enabled chipsets, motherboards and CPUs: http://wiki.xensource.com/xenwiki/VTdHowTo

If your hardware doesn’t have an IOMMU (“Intel VT-d” support in case of Intel – “AMD I/O Virtualization Technology” support in case of AMD), you’ll not be able to assign devices in KVM. Some work towards allowing this were done, but the code never made it into KVM, due to various issues with the code. At the moment it doesn’t seem like device assignment without hardware support, will ever be integrated into KVM.

Assignment of graphics cards are not officially supported at the moment, but there has been some success passing through a secondary Radeon HD 5850 as a VM’s secondary display.

资料:http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM

在host选择PCI pass through设备

reboot and verify that your system has IOMMU support

AMD Machine

dmesg | grep AMD-Vi
 ...
 AMD-Vi: Enabling IOMMU at 0000:00:00.2 cap 0x40
 AMD-Vi: Lazy IO/TLB flushing enabled
 AMD-Vi: Initialized for Passthrough Mode
 ...

Intel Machine

dmesg | grep -e DMAR -e IOMMU
...
DMAR:DRHD base: 0x000000feb03000 flags: 0x0
IOMMU feb03000: ver 1:0 cap c9008020e30260 ecap 1000
...

If you get no output you’ll need to fix this before moving on. Check if your hardware supports VT-d and check that it has been enabled in BIOS.

NOTE: If you still get an error “No IOMMU found.” Check dmesg for errors suggesting your BIOS is broken. Another possible reason: CONFIG_DMAR_DEFAULT_ON is not set. In that case, pass “intel_iommu=on” as kernel parameter to enable it. AMD uses different kernel parameter than Intel, on AMD you need to pass “iommu=pt iommu=1”.

请看附录:No IOMMU found 解决

选择要使用的透传设备

# lspci -nn
00:00.0 Host bridge [0600]: Intel Corporation 2nd Generation Core Processor Family DRAM Controller [8086:0100] (rev 09)
......
00:1b.0 Audio device [0403]: Intel Corporation 6 Series/C200 Series Chipset Family High Definition Audio Controller [8086:1c20] (rev 04)
.....
00:1f.3 SMBus [0c05]: Intel Corporation 6 Series/C200 Series Chipset Family SMBus Controller [8086:1c22] (rev 04)

友情提示:使用透传设备时,拿USB控制器作实验,可能鼠标键盘不能使用.请谨慎.

将设备从宿主机上解除绑定

使用echo命令,将设备从host机器上解除绑定,将来用于guest机器. For example:

echo "8086 1c20" > /sys/bus/pci/drivers/pci-stub/new_id
echo 0000:00:1b.0 > /sys/bus/pci/devices/0000:00:1b.0/driver/unbind
echo 0000:00:1b.0 > /sys/bus/pci/drivers/pci-stub/bind

关闭虚拟机

关闭虚拟机,修改配置文件.

使用libvirt进行pci pass through

修改虚拟机配置文件

<devices> …
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <source>
         <address domain='0x000' bus='0x00′ slot='0x1b' function='0x0' />
      </source>
   </hostdev>
</devices>

在修改完虚拟机配置文件后,运行虚拟机.

使用qemu进行pci pass through

使用qemu进行pci pass through也是一样的简单的.我们需要一个已经创建好操作系统的虚拟机.

在qemu命令行运行以下命令以启动虚拟机

/usr/bin/qemu-kvm -name vdisk -enable-kvm -m 512 -smp 2 \
-hda /mnt/nfs/vdisk.img \
-monitor stdio \
-vnc 0.0.0.0:0 \
-device pci-assign,host=00:1b.0

这样就将设备挂载到虚拟机上了.

  • 参数-device pci-assign,host=00:1b.0说的是使用一个pci设备,并提供一个设备的地址.
  • 参数-monitor stdio是使用一个标准的控制台输出.在命令行中进行输入命令,等等迁移的时候也在这里输入命令.

附录1:No IOMMU found 解决

启动虚拟机的时候出现了iommu的问题.以供大家参考

1.查看错误日志说明

在配置好XML文件后,启动虚拟机,遇到一个问题.

error: Failed to start domain vdisk
error: Unable to read from monitor: Connection reset by peer

查看虚拟机日志( cat /var/log/libvirt/qemu/vdisk.log )信息.

char device redirected to /dev/pts/3
No IOMMU found. Unable to assign device "hostdev0"
qemu-system-x86_64: -device pci-assign,configfd=20,host=00:1b.0,id=hostdev0,bus=pci.0,addr=0x4: Device 'pci-assign' could not be initialized
2013-07-08 06:41:23.256+0000: shutting down

上网查阅资料,说是要在BIOS上设置虚拟化,然后在引导程序里也要设置iommu.可以查看一下自己的电脑信息是否开启了.

2.查看信息gurb的引导信息

# cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-3.9.6-200.fc18.x86_64 root=/dev/mapper/fedora-home ro rd.lvm.lv=fedora/swap rd.md=0 rd.dm=0 rd.lvm.lv=fedora/home rd.luks=0 vconsole.keymap=us rhgb quiet LANG=en_US.UTF-8

可以发现,我的还未开启intel_iommu=on选项.所以接下来我们来激活它.

3.激活intel_iommu=on

Activate Intel VT-d in the kernel

Activate Intel VT-d in the kernel by appending the intel_iommu=on parameter to the kernel line of the kernel line in the/boot/grub/grub.conf file. The example below is a modified grub.conf file with Intel VT-d activated.

对于intel的cpu和amd的cpu,在grub配置上是不同的,具体的配置请参考文章:http://pve.proxmox.com/wiki/Pci_passthrough

4.更新grub

在编辑完grub文件后,需要更新

grub2-mkconfig   # fedora arch centos
update-grub            # ubuntu debian

5.重启电脑,使其生效

# cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-3.9.6-200.fc18.x86_64 root=/dev/mapper/fedora-home ro rd.lvm.lv=fedora/swap rd.md=0 rd.dm=0 rd.lvm.lv=fedora/home rd.luks=0 vconsole.keymap=us rhgb quiet intel_iommu=on LANG=en_US.UTF-8

发现开机已经启动了inte _iommu=on了.再次启动虚拟机已经就不会出现这个bug了.

附录2 PCI pass through 失败要关闭SELinux

我用的是Fedora 18 ,将SELinux给disalbed了,但是发现PCI pass through出先问题.上网看到文章PCI passthrough fails in qemu-kvm unless selinux is disabled 说,要将selinux设置成permissive模式,于是这个问题解决了.

参考资料

分类: 虚拟化

Linux永久改变hostname

Linux的hostname有时候有些作用,比如在shell中显示用户名@主机名

临时改变hostname

[root@localhost ~]# hostname # show current hostname
localhost.localdomain

[root@localhost ~]# hostname domain # change hostname
[root@localhost ~]# hostname
domain

永久改变hostname

[root@localhost ~]# vi /etc/hostname    # change
domain
[root@localhost ~]# exit

重新登录

[root@domain ~]# hostname
domain

分类: Linux

Linux添加、创建新用户

给Linux添加新用户,新建用户,新建帐号

添加用户组

sudo groupadd groupname

添加用户

sudo useradd username -m -s /sbin/nologin -d /home/username -g groupname
-s /sbin/nologin 设置不能登陆 -s /bin/false(老方法) 也行
-d 设置用户主目录
-g 用户组
-m 创建用户目录

useradd的具体参数为

[root@317304 ~]# useradd --help
Usage: useradd [options] LOGIN

Options:
  -b, --base-dir BASE_DIR       base directory for the home directory of the
                                new account
  -c, --comment COMMENT         GECOS field of the new account
  -d, --home-dir HOME_DIR       home directory of the new account
  -D, --defaults                print or change default useradd configuration
  -e, --expiredate EXPIRE_DATE  expiration date of the new account
  -f, --inactive INACTIVE       password inactivity period of the new account
  -g, --gid GROUP               name or ID of the primary group of the new
                                account
  -G, --groups GROUPS           list of supplementary groups of the new
                                account
  -h, --help                    display this help message and exit
  -k, --skel SKEL_DIR           use this alternative skeleton directory
  -K, --key KEY=VALUE           override /etc/login.defs defaults
  -l, --no-log-init             do not add the user to the lastlog and
                                faillog databases
  -m, --create-home             create the user's home directory
  -M, --no-create-home          do not create the user's home directory
  -N, --no-user-group           do not create a group with the same name as
                                the user
  -o, --non-unique              allow to create users with duplicate
                                (non-unique) UID
  -p, --password PASSWORD       encrypted password of the new account
  -r, --system                  create a system account
  -s, --shell SHELL             login shell of the new account
  -u, --uid UID                 user ID of the new account
  -U, --user-group              create a group with the same name as the user
  -Z, --selinux-user SEUSER     use a specific SEUSER for the SELinux user mapping

更改用户登录权限

在增加了-s /sbin/nologin 参数后,那么这个帐号就不能登陆了,如果想要恢复登陆使用

sudo usermod -s /bin/bash username

禁用用户登录权限

sudo usermod -s /sbin/nologin username

设置密码

给用户设置密码,这样帐号就能使用了。

sudo passwd username

删除用户

删除用户

sudo userdel username

分类: Linux

在虚拟机中安装CentOS操作系统

打算在虚拟机中安装一个centos,然后用来学习服务器的配置,也算是为了将来买vps的准备吧,反正内存也比较大,尽管我自己使用的Ubuntu,但是不想乱安装软件,还是用来虚拟机来,免的捣鼓坏了可以快速还原。

下载centos光盘安装镜像

下载Centos的iso源文件, 我是在USTC上下载的,下载地址为http://mirrors.ustc.edu.cn/centos/6.3/isos/x86_64/CentOS-6.3-x86_64-minimal.iso

在虚拟机中安装centos

在虚拟机中新建一个Linux系统,并在虚拟光盘中添加iso文件,运行虚拟机,进入系统。

  1. 运行后,有个选项,选择”Install or upgrade an existing system”,等待一系列检查,
  2. 有一个”Disc found”,检测光盘是否完整,一般没用,我选择跳过了。然后继续等待。
  3. 出现”Welcome to CentOS!”,选择”OK”。
  4. 在”Language Selection”语言选择中,我选择默认的英语”English”。
  5. 在”Keyboard Selection”键盘选择,默认”us”。
  6. “Time Zone Selection”时区选择,我选择”Asia/Shanghai”上海。
  7. 输入root密码。
  8. 选择分区,我将整块硬盘都使用了。然后又是等待,这次等待时间较长。不过它怎么就从网上下载东西呢,果断断网。貌似不结束,重启,唉。 估计得等到连接超时才跳过。
  9. 安装完后,重启计算机,就可以使用root用户登录了。

使用root账户登录成功。

系统默认使用DHCP获得ip,虚拟机中使用的是NAT转换,不支持ipv6,我使用桥接功能,这样我能使用ipv6。

接下来要安装一下ssh服务器功能。

分类: Linux, 网站建设

探索linux的触摸板和fn键输入事件

因为上一篇文章Ubuntu12.04通过xinput禁用及启用联想笔记本的触摸板,想通过模拟Fn+F8按键输入禁用触摸板的功能,被禁用后的触摸板上的灯会亮,看着比较安心。于是通过查找各种方法模拟键盘输入。

本想通过bash模拟按键输入,没有成功,只找到一个小命令xdotool key Ctrl+F8,但是使用Fn也是不能识别。想通过C语言或者C++来模拟Fn输入,上网搜索英文、中文结果,也没发现,只介绍了其他普通键的模拟,没有更详细的说明Fn的模拟。网上有关Fn的按键模拟都没有结果。无奈。

在搜索中发现Fn不受OS控制,是由硬件实现的,有的笔记本可以通过BIOS的设置Fn和ctrl互换。但我还是继续查找,没有结果。那就先暂时认为Fn是由硬件实现的吧,不能通过软件模拟出来效果。以下是我做的小测试,勉强能说服我吧。以后再讨论Fn的事情。

我们可以查看下Linux系统中的 /dev/input/event事件, 我们先通过xinput查看一下笔记本的键盘,通过xinput list 看出结果

ddd@ddd:~$ xinput
⎡ Virtual core pointer                      id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ MLK rapoo 1800                            id=11   [slave  pointer  (2)]
⎜   ↳ ETPS/2 Elantech Touchpad                  id=14   [slave  pointer  (2)]
⎣ Virtual core keyboard                     id=3    [master keyboard (2)]
    ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
    ↳ Power Button                              id=6    [slave  keyboard (3)]
    ↳ Video Bus                                 id=7    [slave  keyboard (3)]
    ↳ Video Bus                                 id=8    [slave  keyboard (3)]
    ↳ Sleep Button                              id=9    [slave  keyboard (3)]
    ↳ MLK rapoo 1800                            id=10   [slave  keyboard (3)]
    ↳ Lenovo EasyCamera                         id=12   [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard              id=13   [slave  keyboard (3)]
    ↳ Ideapad extra buttons                     id=15   [slave  keyboard (3)]

其中”AT Translated Set 2 keyboard“是我的笔记本键盘,查看对应的/dev/input/event是第几个事件。

ddd@ddd:~$ xinput list-props 13
Device 'AT Translated Set 2 keyboard':
    Device Enabled (132):   1
    Coordinate Transformation Matrix (134): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000
    Device Product ID (249):    1, 1
    Device Node (250):  "/dev/input/event3"

可以看出,我的笔记本的键盘对应的是”/dev/input/event3“。接下来我们就可以通过查看”/dev/input/event3“来看看Linux系统中键盘都有那些数据输入。

sudo hexdump /dev/input/event3

然后就出现等待的状态,我们通过笔记本的键盘敲一下按键,会有9行的数据出来。

0000000 1d34 4fd7 0000 0000 68ae 0002 0000 0000
0000010 0004 0004 001e 0000 1d34 4fd7 0000 0000
0000020 68b4 0002 0000 0000 0001 001e 0001 0000
0000030 1d34 4fd7 0000 0000 68b5 0002 0000 0000
0000040 0000 0000 0000 0000 1d34 4fd7 0000 0000
0000050 57c3 0003 0000 0000 0004 0004 001e 0000
0000060 1d34 4fd7 0000 0000 57c9 0003 0000 0000
0000070 0001 001e 0000 0000 1d34 4fd7 0000 0000
0000080 57c9 0003 0000 0000 0000 0000 0000 0000

说明一下是什么意思吧。 这个在 /linux/input.h中的数据结构中有说明,我们看看具体的数据结构是什么

struct input_event {
         struct timeval time;   //事件发生的时间
         __u16 type;        //事件类类型:按键和移动鼠标就是不同类型
         __u16 code;
         __s32 value;       //事件值:按键a和按键b就对应不同值
};

其中有一行会出现自己敲的字符啊”a”,我在结果中省去了。因为我还有一个USB键盘,我在USB键盘中敲字符,在shell中不会出现16进制的数据,只出现我敲的字符。 通过按下Fn键,可以发现我的shell中不显示16进制数据,也不显示任何字符,空空如也。这可以说明,fn键没有触发Linux输入事件,没有收到Linux的监听。 通过 xinput set-prop ‘AT Translated Set 2 keyboard’ ‘Device Enabled’ 0 禁用笔记本的键盘,发现fn+f8照常能工作,即fn键不再Linux设备监控中。但是直接按Fn没有输入效果。和Fn组合就有效果了。奇怪,这个组合不知道在底层是怎么实现的? 不过在查看具体的头文件/linux/input.h,在618行中看见定义KEY_FN及一些其他组合例如

#define KEY_FN            0x1d0
#define KEY_FN_ESC      0x1d1
#define KEY_FN_F1       0x1d2
#define KEY_FN_F2       0x1d3
#define KEY_FN_F3       0x1d4

,难道可以模拟Fn键,这激发了我继续探索的动力,先留这下次查找一些资料看看。

分类: Linux

Debian 系统修改语言设置成英文

今天安装了一个Debian的虚拟机,安装的时候本来想选英语的,但是时区只能用美国的时区,于是就换上了中文的,没有提示选择时区。

发现在shell中文还是乱码,于是毅然的把语言更改成英语的。打开文件locale

sudo vi /etc/default/locale

显示

LANG="zh_CN.UTF-8"
LANGUAGE="zh_CN:zh"

将其内容更改成

LANG="en_US.UTF-8"
LANGUAGE="en_US:en"

然后重启reboot机器。

在修改的过程中,vi已经忘记了差不多了,导致修改起来非常纠结,勉强给修改完成。后来想给debian安装一个vim的,提示找不到定位源。后来运行了apt-get update后可以安装了。

———–update on 6月22日——–

虽然之前的能够将中文改成英文,但是在使用locale命令时时会出现

locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory

Ubuntu wiki Locale 修改上说是因为 en-US.UTF-8 没有安装。得知通过

dpkg-reconfigure locales

修改,在选项中选择en-US.UTF-8 按空格选中。然后简单的按 ok 键就好了。这下才算正确把中文环境的系统更换成英文的环境的系统。

Reference:Debian Locale 说明

分类: Linux

较早的文章

Copyright © 2017 东东东 陈煜东的博客 粤ICP备13059639号-1

SITEMAP回到顶部 ↑