原文:http://amitsaha.github.io/site/notes/articles/python_linux/article.html

In this article, we will explore the Python programming language as a tool to retrieve various information about a system running Linux. Let’s get started.

Which Python?

When I refer to Python, I am referring to CPython 2 (2.7 to be exact). I will mention it explicitly when the same code won’t work with CPython 3 (3.3) and provide the alternative code, explaining the differences. Just to make sure that you have CPython installed, type python orpython3 from the terminal and you should see the Python prompt displayed in your terminal.

Please note that all the programs have their first line as #!/usr/bin/env python meaning that, we want the Python interpreter to execute these scripts. Hence, if you make your script executable using chmod +x your-script.py, you can execute it using ./your-script.py (which is what you will see in this article).

Exploring the platform module

The platform module in the standard library has a number of functions which allow us to retrieve various system information. Let us start the Python interpreter and explore some of them, starting with the platform.uname() function:

  1. >>> import platform
  2. >>> platform.uname()
  3. ('Linux', 'fedora.echorand', '3.7.4-204.fc18.x86_64', '#1 SMP Wed Jan 23 16:44:29 UTC 2013', 'x86_64')

If you are aware of the uname command on Linux, you will recognize that this function is an interface of sorts to this command. On Python 2, it returns a tuple consisting of the system type (or Kernel type), hostname, version, release, machine hardware and processor information. You can access individual attributes using indices, like so:

  1. >>> platform.uname()[0]
  2. 'Linux'

On Python 3, the function returns a named tuple:

  1. >>> platform.uname()
  2.  
  3. uname_result(system='Linux', node='fedora.echorand',
  4. release='3.7.4-204.fc18.x86_64', version='#1 SMP Wed Jan 23 16:44:29
  5. UTC 2013', machine='x86_64', processor='x86_64')

Since the returned result is a named tuple, this makes it easy to refer to individual attributes by name rather than having to remember the indices, like so:

  1. >>> platform.uname().system
  2. 'Linux'

The platform module also has direct interfaces to some of the above attributes, like so:

  1. >>> platform.system()
  2. 'Linux'
  3.  
  4. >>> platform.release()
  5. '3.7.4-204.fc18.x86_64'

The linux_distribution() function returns details about the Linux distribution you are on. For example, on a Fedora 18 system, this command returns the following information:

  1. >>> platform.linux_distribution()
  2. ('Fedora', '18', 'Spherical Cow')

The result is returned as a tuple consisting of the distribution name, version and the code name. The distributions supported by your particular Python version can be obtained by printing the value of the _supported_dists attribute:

  1. >>> platform._supported_dists
  2. ('SuSE', 'debian', 'fedora', 'redhat', 'centos', 'mandrake',
  3. 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
  4. 'UnitedLinux', 'turbolinux')

If your Linux distribution is not one of these (or a derivative of one of these), then you will likely not see any useful information from the above function call.

The final function from the platform module, we will look at is the architecture() function. When you call the function without any arguments, this function returns a tuple consisting of the bit architecture and the executable format of the Python executable, like so:

  1. >>> platform.architecture()
  2. ('64bit', 'ELF')

On a 32-bit Linux system, you would see:

  1. >>> platform.architecture()
  2. ('32bit', 'ELF')

You will get similar results if you specify any other executable on the system, like so:

  1. >>> platform.architecture(executable='/usr/bin/ls')
  2. ('64bit', 'ELF')

You are encouraged to explore other functions of the platform module which among others, allow you to find the current Python version you are running. If you are keen to know how this module retrieves this information, the Lib/platform.py file in the Python source directory is where you should look into.

The os and sys modules are also of interest to retrieve certain system attributes such as the native byteorder. Next, we move beyond the Python standard library modules to explore some generic approaches to access the information on a Linux system made available via theproc and sysfs file systems. It is to be noted that the information made available via these filesystems will vary between various hardware architectures and hence you should keep that in mind while reading this article and also writing scripts which attempt to retrieve information from these files.

CPU Information

The file /proc/cpuinfo contains information about the processing units on your system. For example, here is a Python version of what the Linux command cat /proc/cpuinfo would do:

  1. #! /usr/bin/env python
  2. """ print out the /proc/cpuinfo
  3. file
  4. """
  5.  
  6. from __future__ import print_function
  7.  
  8. with open('/proc/cpuinfo') as f:
  9. for line in f:
  10. print(line.rstrip('\n'))

When you execute this program either using Python 2 or Python 3, you should see all the contents of /proc/cpuinfo dumped on your screen (In the above program, the rstrip() method removes the trailing newline character from the end of each line).

The next code listing uses the startswith() string method to display the models of your processing units:

  1. #! /usr/bin/env python
  2.  
  3. """ Print the model of your
  4. processing units
  5.  
  6. """
  7.  
  8. from __future__ import print_function
  9.  
  10. with open('/proc/cpuinfo') as f:
  11. for line in f:
  12. # Ignore the blank line separating the information between
  13. # details about two processing units
  14. if line.strip():
  15. if line.rstrip('\n').startswith('model name'):
  16. model_name = line.rstrip('\n').split(':')[1]
  17. print(model_name)

When you run this program, you should see the model names of each of your processing units. For example, here is what I see on my computer:

  1. Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
  2. Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
  3. Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
  4. Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz

We have so far seen a couple of ways to find the architecture of the computer system we are on. To be technically correct, both those approaches actually report the architecture of the kernel your system is running. So, if your computer is actually a 64-bit computer, but is running a 32-bit kernel, then the above methods will report it as having a 32-bit architecture. To find the true architecture of the computer you can look for the lm flag in the list of flags in /proc/cpuinfo. The lm flag stands for long mode and is only present on computers with a 64-bit architecture. The next program shows how you can do this:

  1. #! /usr/bin/env python
  2.  
  3. """ Find the real bit architecture
  4. """
  5.  
  6. from __future__ import print_function
  7.  
  8. with open('/proc/cpuinfo') as f:
  9. for line in f:
  10. # Ignore the blank line separating the information between
  11. # details about two processing units
  12. if line.strip():
  13. if line.rstrip('\n').startswith('flags') \
  14. or line.rstrip('\n').startswith('Features'):
  15. if 'lm' in line.rstrip('\n').split():
  16. print('64-bit')
  17. else:
  18. print('32-bit')

As we have seen so far, it is possible to read the /proc/cpuinfo and use simple text processing techniques to read the data we are looking for. To make it friendlier for other programs to use this data, it is perhaps a better idea to make the contents of /proc/cpuinfoavailable as a standard data structure, such as a dictionary. The idea is simple: if you see the contents of this file, you will find that for each processing unit, there are a number of key, value pairs (in an earlier example, we printed the model name of the processor, here model name was a key). The information about different processing units are separated from each other by a blank line. It is simple to build a dictionary structure which has each of the processing unit’s data as keys. For each of the these keys, the value is all the information about the corresponding processing unit present in the file /proc/cpuinfo. The next listing shows how you can do so.

  1. #!/usr/bin/env/ python
  2.  
  3. """
  4. /proc/cpuinfo as a Python dict
  5. """
  6. from __future__ import print_function
  7. from collections import OrderedDict
  8. import pprint
  9.  
  10. def cpuinfo():
  11. ''' Return the information in /proc/cpuinfo
  12. as a dictionary in the following format:
  13. cpu_info['proc0']={...}
  14. cpu_info['proc1']={...}
  15.  
  16. '''
  17.  
  18. cpuinfo=OrderedDict()
  19. procinfo=OrderedDict()
  20.  
  21. nprocs = 0
  22. with open('/proc/cpuinfo') as f:
  23. for line in f:
  24. if not line.strip():
  25. # end of one processor
  26. cpuinfo['proc%s' % nprocs] = procinfo
  27. nprocs=nprocs+1
  28. # Reset
  29. procinfo=OrderedDict()
  30. else:
  31. if len(line.split(':')) == 2:
  32. procinfo[line.split(':')[0].strip()] = line.split(':')[1].strip()
  33. else:
  34. procinfo[line.split(':')[0].strip()] = ''
  35.  
  36. return cpuinfo
  37.  
  38. if __name__=='__main__':
  39. cpuinfo = cpuinfo()
  40. for processor in cpuinfo.keys():
  41. print(cpuinfo[processor]['model name'])

This code uses an OrderedDict (Ordered dictionary) instead of a usual dictionary so that the key and values are stored in the order which they are found in the file. Hence, the data for the first processing unit is followed by the data about the second processing unit and so on. If you call this function, it returns you a dictionary. The keys of dictionary are each processing unit with. You can then use to sieve for the information you are looking for (as demonstrated in the if __name__=='__main__' block). The above program when run will once again print the model name of each processing unit (as indicated by the statement print(cpuinfo[processor]['model name']):

  1. Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
  2. Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
  3. Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
  4. Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz

Memory Information

Similar to /proc/cpuinfo, the file /proc/meminfo contains information about the main memory on your computer. The next program creates a dictionary from the contents of this file and dumps it.

  1. #!/usr/bin/env python
  2.  
  3. from __future__ import print_function
  4. from collections import OrderedDict
  5.  
  6. def meminfo():
  7. ''' Return the information in /proc/meminfo
  8. as a dictionary '''
  9. meminfo=OrderedDict()
  10.  
  11. with open('/proc/meminfo') as f:
  12. for line in f:
  13. meminfo[line.split(':')[0]] = line.split(':')[1].strip()
  14. return meminfo
  15.  
  16. if __name__=='__main__':
  17. #print(meminfo())
  18.  
  19. meminfo = meminfo()
  20. print('Total memory: {0}'.format(meminfo['MemTotal']))
  21. print('Free memory: {0}'.format(meminfo['MemFree']))

As earlier, you could also access any specific information you are looking for by using that as a key (shown in the if __name__==__main__block). When you execute the program, you should see an output similar to the following:

  1. Total memory: 7897012 kB
  2. Free memory: 249508 kB

Network Statistics

Next, we explore the network devices on our computer system. We will retrieve the network interfaces on the system and the data bytes sent and recieved by them since your system reboot. The /proc/net/dev file makes this information available. If you examine the contents of this file, you will notice that the first two lines contain header information - i.e. the first column of this file is the network interface name, the second and the third columns display information about the received and the transmitted bytes (such as total bytes sent, number of packets, errors, etc.). Our interest here is to extract the total data sent and recieved by the different network devices. The next listing shows how we can extract this information from /proc/net/dev:

  1. #!/usr/bin/env python
  2. from __future__ import print_function
  3. from collections import namedtuple
  4.  
  5. def netdevs():
  6. ''' RX and TX bytes for each of the network devices '''
  7.  
  8. with open('/proc/net/dev') as f:
  9. net_dump = f.readlines()
  10.  
  11. device_data={}
  12. data = namedtuple('data',['rx','tx'])
  13. for line in net_dump[2:]:
  14. line = line.split(':')
  15. if line[0].strip() != 'lo':
  16. device_data[line[0].strip()] = data(float(line[1].split()[0])/(1024.0*1024.0),
  17. float(line[1].split()[8])/(1024.0*1024.0))
  18.  
  19. return device_data
  20.  
  21. if __name__=='__main__':
  22.  
  23. netdevs = netdevs()
  24. for dev in netdevs.keys():
  25. print('{0}: {1} MiB {2} MiB'.format(dev, netdevs[dev].rx, netdevs[dev].tx))

When you run the above program, the output should display your network devices along with the total recieved and transmitted data in MiB since your last reboot as shown below:

  1. em1: 0.0 MiB 0.0 MiB
  2. wlan0: 2651.40951061 MiB 183.173976898 MiB

You could probably couple this with a persistent data storage mechanism to write your own data usage monitoring program.

Processes

The /proc directory also contains a directory each for all the running processes. The directory names are the same as the process IDs for these processes. Hence, if you scan /proc for all directories which have digits as their names, you will have a list of process IDs of all the currently running processes. The function process_list() in the next listing returns a list with process IDs of all the currently running processes. The length of this list will hence be the total number of processes running on the system as you will see when you execute the above program.

  1. #!/usr/bin/env python
  2. """
  3. List of all process IDs currently active
  4. """
  5.  
  6. from __future__ import print_function
  7. import os
  8. def process_list():
  9.  
  10. pids = []
  11. for subdir in os.listdir('/proc'):
  12. if subdir.isdigit():
  13. pids.append(subdir)
  14.  
  15. return pids
  16.  
  17. if __name__=='__main__':
  18.  
  19. pids = process_list()
  20. print('Total number of running processes:: {0}'.format(len(pids)))

The above program when executed will show an output similar to:

  1. Total number of running processes:: 229

Each of the process directories contain number of other files and directories which contain various information about the invoking command of the process, the shared libraries its using, and others.

Block devices

The next program lists all the block devices by reading from the sysfs virtual file system. The block devices on your system can be found in the /sys/block directory. Thus, you may have directories such as /sys/block/sda, /sys/block/sdb and so on. To find all such devices, we perform a scan of the /sys/block directory using a simple regular expression to express the block devices we are interested in finding.

  1. #!/usr/bin/env python
  2.  
  3. """
  4. Read block device data from sysfs
  5. """
  6.  
  7. from __future__ import print_function
  8. import glob
  9. import re
  10. import os
  11.  
  12. # Add any other device pattern to read from
  13. dev_pattern = ['sd.*','mmcblk*']
  14.  
  15. def size(device):
  16. nr_sectors = open(device+'/size').read().rstrip('\n')
  17. sect_size = open(device+'/queue/hw_sector_size').read().rstrip('\n')
  18.  
  19. # The sect_size is in bytes, so we convert it to GiB and then send it back
  20. return (float(nr_sectors)*float(sect_size))/(1024.0*1024.0*1024.0)
  21.  
  22. def detect_devs():
  23. for device in glob.glob('/sys/block/*'):
  24. for pattern in dev_pattern:
  25. if re.compile(pattern).match(os.path.basename(device)):
  26. print('Device:: {0}, Size:: {1} GiB'.format(device, size(device)))
  27.  
  28. if __name__=='__main__':
  29. detect_devs()

If you run this program, you will see output similar to as follows:

  1. Device:: /sys/block/sda, Size:: 465.761741638 GiB
  2. Device:: /sys/block/mmcblk0, Size:: 3.70703125 GiB

When I run the program, I had a SD memory card plugged in as well and hence you can see that the program detects it. You can extend this program to recognize other block devices (such as virtual hard disks) as well.

Building command line utilities

One ubiquitious part of all Linux command line utilities is that they allow the user to specify command line arguments to customise the default behavior of the program. The argparse module allows your program to have an interface similar to built-in Linux utilities. The next listing shows a program which retrieves all the users on your system and prints their login shells (using the pwd standard library module):

  1. #!/usr/bin/env python
  2.  
  3. """
  4. Print all the users and their login shells
  5. """
  6.  
  7. from __future__ import print_function
  8. import pwd
  9.  
  10. # Get the users from /etc/passwd
  11. def getusers():
  12. users = pwd.getpwall()
  13. for user in users:
  14. print('{0}:{1}'.format(user.pw_name, user.pw_shell))
  15.  
  16. if __name__=='__main__':
  17. getusers()

When run the program above, it will print all the users on your system and their login shells.

Now, let us say that you want the program user to be able to choose whether he or she wants to see the system users (like daemon,apache). We will see a first use of the argparse module to implement this feature in by extending the previous listing as follows.

  1. #!/usr/bin/env python
  2.  
  3. """
  4. Utility to play around with users and passwords on a Linux system
  5. """
  6.  
  7. from __future__ import print_function
  8. import pwd
  9. import argparse
  10. import os
  11.  
  12. def read_login_defs():
  13.  
  14. uid_min = None
  15. uid_max = None
  16.  
  17. if os.path.exists('/etc/login.defs'):
  18. with open('/etc/login.defs') as f:
  19. login_data = f.readlines()
  20.  
  21. for line in login_data:
  22. if line.startswith('UID_MIN'):
  23. uid_min = int(line.split()[1].strip())
  24.  
  25. if line.startswith('UID_MAX'):
  26. uid_max = int(line.split()[1].strip())
  27.  
  28. return uid_min, uid_max
  29.  
  30. # Get the users from /etc/passwd
  31. def getusers(no_system=False):
  32.  
  33. uid_min, uid_max = read_login_defs()
  34.  
  35. if uid_min is None:
  36. uid_min = 1000
  37. if uid_max is None:
  38. uid_max = 60000
  39.  
  40. users = pwd.getpwall()
  41. for user in users:
  42. if no_system:
  43. if user.pw_uid >= uid_min and user.pw_uid <= uid_max:
  44. print('{0}:{1}'.format(user.pw_name, user.pw_shell))
  45. else:
  46. print('{0}:{1}'.format(user.pw_name, user.pw_shell))
  47.  
  48. if __name__=='__main__':
  49.  
  50. parser = argparse.ArgumentParser(description='User/Password Utility')
  51.  
  52. parser.add_argument('--no-system', action='store_true',dest='no_system',
  53. default = False, help='Specify to omit system users')
  54.  
  55. args = parser.parse_args()
  56. getusers(args.no_system)

On executing the above program with the --help option, you will see a nice help message with the available options (and what they do):

  1. $ ./getusers.py --help
  2. usage: getusers.py [-h] [--no-system]
  3.  
  4. User/Password Utility
  5.  
  6. optional arguments:
  7. -h, --help show this help message and exit
  8. --no-system Specify to omit system users

An example invocation of the above program is as follows:

  1. $ ./getusers.py --no-system
  2. gene:/bin/bash

When you pass an invalid parameter, the program complains:

  1. $ ./getusers.py --param
  2. usage: getusers.py [-h] [--no-system]
  3. getusers.py: error: unrecognized arguments: --param

Let us try to understand in brief how we used argparse in the above program. The statement: parser =argparse.ArgumentParser(description='User/Password Utility') creates a new ArgumentParser object with an optional description of what this program does.

Then, we add the arguments that we want the program to recognize using the add_argument() method in the next statement:parser.add_argument('--no-system', action='store_true', dest='no_system', default = False, help='Specify to omit systemusers'). The first argument to this method is the name of the option that the program user will supply as an argument while invoking the program, the next parameter action=store_true indicates that this is a boolean option. That is, its presence or absence affects the program behavior in some way. The dest parameter specifies the variable in which the value that the value of this option will be available to the program. If this option is not supplied by the user, the default value is False which is indicated by the parameter default = Falseand the last parameter is the help message that the program displays about this option. Finally, the arguments are parsed using theparse_args() method: args = parser.parse_args(). Once the parsing is done, the values of the options supplied by the user can be retrieved using the syntax args.option_dest, where option_dest is the dest variable that you specified while setting up the arguments. This statement: getusers(args.no_system) calls the getusers() function with the option value for no_system supplied by the user.

The next program shows how you can specify options which allow the user to specify non-boolean preferences to your program. This program is a rewrite of Listing 6, with the additional option to specify the network device you may be interested in.

  1. #!/usr/bin/env python
  2. from __future__ import print_function
  3. from collections import namedtuple
  4. import argparse
  5.  
  6. def netdevs(iface=None):
  7. ''' RX and TX bytes for each of the network devices '''
  8.  
  9. with open('/proc/net/dev') as f:
  10. net_dump = f.readlines()
  11.  
  12. device_data={}
  13. data = namedtuple('data',['rx','tx'])
  14. for line in net_dump[2:]:
  15. line = line.split(':')
  16. if not iface:
  17. if line[0].strip() != 'lo':
  18. device_data[line[0].strip()] = data(float(line[1].split()[0])/(1024.0*1024.0),
  19. float(line[1].split()[8])/(1024.0*1024.0))
  20. else:
  21. if line[0].strip() == iface:
  22. device_data[line[0].strip()] = data(float(line[1].split()[0])/(1024.0*1024.0),
  23. float(line[1].split()[8])/(1024.0*1024.0))
  24. return device_data
  25.  
  26. if __name__=='__main__':
  27.  
  28. parser = argparse.ArgumentParser(description='Network Interface Usage Monitor')
  29. parser.add_argument('-i','--interface', dest='iface',
  30. help='Network interface')
  31.  
  32. args = parser.parse_args()
  33.  
  34. netdevs = netdevs(iface = args.iface)
  35. for dev in netdevs.keys():
  36. print('{0}: {1} MiB {2} MiB'.format(dev, netdevs[dev].rx, netdevs[dev].tx))

When you execute the program without any arguments, it behaves exactly as the earlier version. However, you can also specify the network device you may be interested in. For example:

  1. $ ./net_devs_2.py
  2.  
  3. em1: 0.0 MiB 0.0 MiB
  4. wlan0: 146.099492073 MiB 12.9737148285 MiB
  5. virbr1: 0.0 MiB 0.0 MiB
  6. virbr1-nic: 0.0 MiB 0.0 MiB
  7.  
  8. $ ./net_devs_2.py --help
  9. usage: net_devs_2.py [-h] [-i IFACE]
  10.  
  11. Network Interface Usage Monitor
  12.  
  13. optional arguments:
  14. -h, --help show this help message and exit
  15. -i IFACE, --interface IFACE
  16. Network interface
  17.  
  18. $ ./net_devs_2.py -i wlan0
  19. wlan0: 146.100307465 MiB 12.9777050018 MiB

System-wide availability of your scripts

With the help of this article, you may have been able to write one or more useful scripts for yourself which you want to use everyday like any other Linux command. The easiest way to do is make this script executable and setup a BASH alias to this script. You could also remove the .py extension and place this file in a standard location such as /usr/local/sbin.

Other useful standard library modules

Besides the standard library modules we have already looked at in this article so far, there are number of other standard modules which may be useful: subprocess, ConfigParser, readline and curses.

What next?

At this stage, depending on your own experience with Python and exploring Linux internals, you may follow one of the following paths. If you have been writing a lot of shell scripts/command pipelines to explore various Linux internals, take a look at Python. If you wanted a easier way to write your own utility scripts for performing various tasks, take a look at Python. Lastly, if you have been using Python for programming of other kinds on Linux, have fun using Python for exploring Linux internals.

转:python获取linux系统及性能信息的更多相关文章

  1. 使用Python获取Linux系统的各种信息

    哪个Python版本? 当我提及Python,所指的就是CPython 2(准确的是2.7).我会显式提醒那些相同的代码在CPython 3 (3.3)上是不工作的,以及提供一份解释不同之处的备选代码 ...

  2. Inxi:获取Linux系统和硬件信息的神器

    导读 在这篇文章里,我们将看到如何使用inxi来获取这些详情信息.在论坛技术支持中,它可以作为调试工具,迅速确定用户的系统配置和硬件信息. Inxi是一个可以获取完整的系统和硬件详情信息的命令行工具, ...

  3. 获取Linux系统运行情况信息

    代码: #include <stdio.h> #include <unistd.h> /* usleep() */ #include <stdlib.h> #inc ...

  4. 用Python获取Linux资源信息的三种方法

    方法一:psutil模块 #!usr/bin/env python # -*- coding: utf-8 -*- import socket import psutil class NodeReso ...

  5. JAVA如何利用Swiger获取Linux系统电脑配置相关信息

    最近开发java应用程序,涉及到获取Linux服务器相关配置的问题,特地网上搜寻了下,采用Swiger包可以直接获取,再次小结一下,以便于以后能方便使用,也便于其他童鞋们学习. 推荐大家参考链接:ht ...

  6. 主机性能监控之wmi 获取系统信息及内存性能信息

    标 题: 主机性能监控之wmi 获取系统信息及内存性能信息作 者: itdef链 接: http://www.cnblogs.com/itdef/p/3990240.html 欢迎转帖 请保持文本完整 ...

  7. python进行linux系统监控

      python进行linux系统监控 Linux系统下: 静态指标信息: 名称 描述 单位 所在文件 mem_total 内存总容量 KB /proc/meminfo disks 磁盘相关信息 - ...

  8. 【转载】Linux系统与性能监控

    原文地址:http://kerrigan.sinaapp.com/post-7.html Linux System and Performance Monitoring http://www.hous ...

  9. Linux系统与性能监控

    原文地址:http://kerrigan.sinaapp.com/post-7.html Linux System and Performance Monitoring http://www.hous ...

随机推荐

  1. redis集群安装

    1.普通安装 安装环境 centos 6.8 1.安装必要包 yum install gcc yum -y install wget 2.下载解压 wget http://download.redis ...

  2. protobuf初体验

    概念介绍 Protocol buffers 是google公司的与语言无关.与平台无关的.可扩张的为序列化话结构数据,就像xml一样,办事更加的小巧.快速.简单.Protocol buffers 目前 ...

  3. Android 动画详解

    这次主要就介绍android动画,android动画目前分为三种形式,Tween Animation 这个只能应用于view对象上面的,Drawable Animation这个是帧动画,就是类似我们有 ...

  4. 各大门户网站的css初始化代码

    腾讯QQ官网 css样式初始 body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select ...

  5. 学霸网站---Alpha+版本测试报告

    说明:由于老师前几天要求交测试报告,本测试报告只针对当时完成的功能进行测试,并不是几天之后要发布的BETA版本,不会有很多差别,但是BETA版本会包含对其中BUG的修复. 学霸网站测试报告 一.引言 ...

  6. android 很多牛叉布局github地址(转)

    原文地址 http://blog.csdn.net/luo15309823081/article/details/41449929 点击可到达github-------https://github.c ...

  7. easyui datagrid 加载两次请求,触发两次ajax 请求 问题

    datagrid初始化的时候请求两次URL 两种情况 1. <table id="gridview" class="easyui-datagrid"> ...

  8. SDN三种模型解析

    数十年前,计算机科学家兼网络作家Andrew S. Tanenbaum讽刺标准过多难以选择,当然现在也是如此,比如软件定义网络模型的数量也很多.但是在考虑部署软件定义网络(SDN)或者试点之前,首先需 ...

  9. Mac Virtual System On Windows

    Win8.1下利用虚拟机安装苹果操作系统 所需文件: 虚拟机:VMware -10.0.1,这个就是中文版的了. 虚拟机密钥生成器:vm10keygen,要对应虚拟机的版本. 虚拟机的插件: unlo ...

  10. Android 图片添加水印图片或者文字

    给图片添加水印的基本思路都是载入原图,添加文字或者载入水印图片,保存图片这三个部分 添加水印图片: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...