2014年7月31日星期四

IOS开发之TableView、多个TableViewCell、自定义Cell、Cell上画画(故事板+代码方式) - 刘东寰

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
IOS开发之TableView、多个TableViewCell、自定义Cell、Cell上画画(故事板+代码方式) - 刘东寰  阅读原文»

最近要做一个项目,有个账户设置界面,看了微博、微信、QQ,他们的账号设置都比较原生态没做什么处理。春雨医生的账号不错,做了许多处理。不说废话直接上代码。

第一步:

//UserTableViewCell.h这里定义第一种Cell
#import <UIKit/UIKit.h>
@interface UserTableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UIImageView
*userviewcellicon;
@property (weak, nonatomic) IBOutlet UILabel
*userviewcellname;
@end
//UserTableViewCell2.h这里定义第二种Cell,
#import <UIKit/UIKit.h>
@interface UserTableViewCell2 : UITableViewCell
@property (weak, nonatomic) IBOutlet UILabel
*name;
@property (weak, nonatomic) IBOutlet UIImageView
*userviewcell2image;
@end

故事板里的TableView和Cell的class和Cell的Identifier就不说了

例:

2、设计好了这些东西后,开始进TableViewController里了:

//UserTableViewController.h
#import <UIKit/UIKit.h>

@interface UserTableViewController : UITableViewController


@property(nonatomic,strong) NSDictionary
*UserViewCellDic;
@property (nonatomic, strong) NSArray
*listGroupname;
@end
//UserTableViewController.m
#import "UserTableViewController.h"
#import "UserTableViewCell.h"
#import "UserTableViewCell2.h"
@interface UserTableViewController ()

@end

@implementation UserTableViewController

- (void)viewDidLoad
{
[super viewDidLoad];

self.tableView.separatorStyle = UITableViewCellAccessoryNone;//去除分割线
NSBundle
*bundle = [NSBundle mainBundle];
NSString
*plistpath = ;
self.UserViewCellDic = [[NSDictionary alloc]initWithContentsOfFile:plistpath];
self.listGroupname
= [self.UserViewCellDic allKeys];
  

self.listGroupname = [self.listGroupname sortedArrayUsingSelector:@selector(compare:)];//排序
}


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView//返回有几个Section
{

return [self.listGroupname count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section//Section头名字设为空
{

NSString *groupName = @" ";
return groupName;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section//每个section的行数
{

NSString
*groupName = [self.listGroupname objectAtIndex:section];
NSArray
*listitem = [self.UserViewCellDic objectForKey:groupName];
return [listitem count];

}
#pragma mark - TableViewDataSource

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

static NSString *UserViewCellIdentifier = @"UserTableViewCell";
static NSString *UserViewCellIdentifier2 = @"UserTableViewCell2";
NSUInteger section
= ;
NSUInteger row
= ;
NSString
*groupName = [self.listGroupname objectAtIndex:section];
NSArray
*listitem = [self.UserViewCellDic objectForKey:groupName];
NSDictionary
*rowDict = [listitem objectAtIndex:row];

if (0 == section) {
UserTableViewCell2
*cell = [tableView dequeueReusableCellWithIdentifier:UserViewCellIdentifier2];
cell.name.text
= [rowDict objectForKey:@"name"];
NSString
*imagePath = [rowDict objectForKey:@"image"];
imagePath
= ;
cell.userviewcell2image.image = ;
cell.accessoryType
= UITableViewCellAccessoryDisclosureIndicator;//最后的箭头
//画线
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 79, 320, 1)];
UIView
*leftview = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 3, 80)];
UIView
*rightview = [[UIView alloc]initWithFrame:CGRectMake(317, 0, 3, 80)];
view.backgroundColor
= ;
leftview.backgroundColor = ;
rightview.backgroundColor = ;
[cell.contentView addSubview:view];
[cell.contentView addSubview:leftview];
[cell.contentView addSubview:rightview];

return cell;
}
else{
UserTableViewCell
*cell = [tableView dequeueReusableCellWithIdentifier:UserViewCellIdentifier];
cell.userviewcellname.text
= [rowDict objectForKey:@"name"];
NSString
*imagePath = [rowDict objectForKey:@"image"];
imagePath
= ;
cell.userviewcellicon.image = ;
cell.accessoryType
= UITableViewCellAccessoryDisclosureIndicator;//java之多线程(Thread) - 龚细军  阅读原文»

1 package DEMO;
2 //主线程
3 public class Example12_2 {
4 public static void main(String [] args )
5 {
6 Thread mydad ; //用Thread声明线程
7 Thread mymom ;
8 baba ba ; //ba是目标对象
9 mom ma ;
10 ba = new baba(); //创建目标对象
11 ma = new mom();
12 mydad = new Thread(ba); //创建线程,其目标对象是bab
13 mymom = new Thread(ma); //创建线程 ,其目标对象是ma
14 mydad.start(); //启动线程
15 mymom.start();
16 //主线程
17 for(int i=1 ;i<=20 ; i++)
18 System.out.print("me"+i+" ");
19
20 }
21 }
22
23 class baba implements Runnable //实现Runnable
24 {
25 public void run()
26 {
27 for(int i=1;i<=20;i++)
28 System.out.print(" dad"+i+" ");
29 }
30 }
31
32 class mom implements Runnable //实现Runnable
33 {
34 public void run()
35 {
36 for(int i=1; i<=20 ;i++)
37 System.out.print("Mon"+i+" ");
38 }
39 }


本文链接:java之多线程(Thread),转载请注明。

阅读更多内容

2014年7月30日星期三

ú°×°Linux×÷

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
ú°×°Linux×÷  阅读原文»

用户名:成长的小虫 文章数:28 评论数:4
访问量:2692:137:390:3 注册日期:2014-05-29

如何实现批量安装Linux操作系统?

一、系统的安装原理:

Linux 系统安装过程:

POST---->Bootloader(ramdisk)----->anaconda系统安装程序

其实,安装操作系统就是把编译好的二进制格式的操作系统导入到目标磁盘中,就要访问硬件。这就涉及到安装程序anaconda能不能驱动目标磁盘。如果,不能驱动目标磁盘的话,该应用程序是无法把文件导入到目标磁盘中的,为了解决这个问题,借助跳板----ramdisk.它就是一个小型的Linux。是位于内存中的。它就能够驱动磁盘。当然它的作用不仅仅是驱动磁盘。

当ramdisk启动起来后,它会执行/sbin/loader加载器,然后就运行:anaconda 程序,在该程序的指引下与用户进行交互完成系统的安装操作。

anaconda程序提供了,两种交互式的接口:

占用内存比较小,安装系统的速度比较快。当然还取决于,你是最小化安装还是。。。
CentOS6内存要求512M才可以启动GUI接口的。
CentOS7内存要求1G才可以启动GUI接口的。

而anaconda安装操作系统过程分为两个阶段:

1、安装前的配置

键盘类型

安装过程中的语言:在anaconda系统安装程序的引导下,显示的语言。一般是英文。

支持使用语言

时区

选择要使用的磁盘设备

规划磁盘的使用:

如:根(/)是否使用LVM。/var、/home、/usr、/usr/local这些存放数据经常变化的目录是否做为单独的分区,

分区使用的文件系统,block块大小等等

swap分区的大小?

选择要安装的包

管理员密码

2、安装阶段(anaconda安装程序就会执照前面的配置执行系统的安装操作)

在目标磁盘创建分区、执行分区格式化

将选定的程序包安装至目标磁盘

安装 bootloader到目标磁盘中。

二、如何实现服务器的批量部署?

1、先实现自动化安装操作系统

既然安装程序提供的是交互式的接口,要人工的干预才可以完成系统的安装,那么怎样实现自动化安装呢?

如果,我们批量部署服务器的时候,还是使用ISO光盘镜像来安装操作系统的话,效率是可想而知的。anaconda很友好的为我们提供了一个功能:

在文本的安装方式下,可以把安装前的配置做成一个ks.cfg格式的文件(使用[root@Node1 ~]# system-config-kickstart & 启动文本窗口,就可以制作ks.cfg文件了)。

在启动ramdisk的时候,把它当做参数,传递给内核。

如下如述:

[root@Node1isolinux]#catisolinux.cfg
defaultvesamenu.c32
displayboot.msg
menubackgroundsplash.jpg
menulabel^Installorupgradeanexistingsystem
kernelvmlinuz------->启动内核
appendinitrd=initrd.imgks=cdrom:isolinux/ks.cfg--------->传递给内核的参数。

说明:

BootLoader,根据配置文件isolinux.cfg展开内核vmlunuz,initrd.img.这就是ramdisk的启动过程。

当ramdisk启动完成后,就会执行/sbin/loader加载器,启动anaconda程序,该程序就会去读取位于cdrom:isolinux目录下的ks.cfg文件。

根据该文件自动完成安装前的配置。

正是由于,我们可以把anaconda安装操作系统过程中的第一段:安装前的配置,做成ks.cfg文件。再不需要人工干预,anaconda

就可以按照该文件完成安装操作系统前的配置。然后直接进入安装阶段(anaconda安装程序就会按照前面的配置执行系统的安装操作)。

这样就可以,实现自动化安装操作系统了。

2、实现ks.cfg和安装源的共享。如何实现网络引导系统安装。

但是,我们批量部署服务器的时候,虽然能够实现了自动化安装操作系统,但不能解决批量的问题,意思是说,在某一时间,只能为一台服务器

安装操作系统,等到该台服务器安装完成后,才可以对下一台服务器,进行系统的安装。不过我们可以制作多个安装盘。如果,我们的安装盘是光盘的话,

则要为第一台服务器提供一个光驱,如果我们安装盘是U盘的话,则要为每一台服务器提供一个U盘。这就不能完全做到自动话部署服务器了,那我们

怎么样解决呢?

既然,我们的系统安装盘,是独享。可以把它做成共享的方式。把ks.cfg文件和安装源(安装树install tree)放到一个公共的地方。每台服务器都可以到

该地方来获取ks.cfg文件和安装源(install tree)。

ks.cfg和安装源的位置可以是本地或网络上任何位置,只要能够获取到。那么,它们怎么定义呢?

(1)、ks.cfg 定义在BootLoader的配置文件中。

(A)、如果安装盘是光盘的话,它的BootLoader的配置文件是:isolinux.cfg. 在append指令中,把ks.cfg文件做为参数传递给内核。

ks=cdrom:/directory/ks.cfg
ks=http://server/path/to/ks.cfg
ks=ftp://username:password@server/path/to/ks.cfg
inst.ks=cdrom:/directory/ks.cfg
Drupal8¨Drupal8°×°-Ubuntu 14.04 LTS  阅读原文»

Drupal8系列(三):Drupal8的安装和初始设置-Ubuntu 14.04 LTS

一、Drupal8的安装

1、搭建环境

由于我们已经安装好了Drush,所以安装Drupal8就会显得十分的简单。但首先还是要先搭建环境:

  • 安装tasksel软件包

    sudoapt-getinstalltasksel
  • 安装LAMP服务(Apache2、Mysql和PHP)

    sudotaskselinstalllamp-server

2、下载Drupal8

我个人的偏好是在自己的用户目录下创建一个sites目录,然后将Drupal8根目录安装在该目录下,然后用 ln -s 将该目录软链接到/var/www/目录中,这样如果要重装系统的话,用户目录下的内容可以保持不变。所以根据我的偏好,所需语句如下:

dldrupal-8.0-alpha13

dl是drush dl的别名,还记得我们在上篇博文中所讲的东西吗?将example.drush.bashrc导入到了~/.bashrc文件中,而它的作用就是可以将冗长的命令缩写,上述语句之后,稍等一会就会得到以下输出:

Projectdrupal(8.0-alpha13)downloadedto[success]
/home/firehare/sites/drupal8/drupal-8.0-alpha13.
Projectdrupalcontains:[success]
-2profiles:standard,minimal
-8themes:stark,bartik,seven,phptemplate,twig,migrate,
drupal_system_listing_compatible_test,testing
-61modules:forum,taxonomy,datetime,search,rest,node,
basic_auth,views,entity_reference,ckeditor,update,color,file,
filter,responsive_image,block_content,config_translation,dblog,
shortcut,user,book,help,path,menu_ui,field,
content_translation,config,contextual,locale,migrate_drupal,
xmlrpc,simpletest,action,options,menu_link,block,breakpoint,
text,image,entity,contact,statistics,serialization,hal,
quickedit,aggregator,ban,rdf,language,tracker,views_ui,tour,
history,field_ui,editor,syslog,telephone,comment,toolbar,link,

并且会在当前目录下生成一个名为drupal-8.0-alpha13的目录,这就是Drupal8的根目录了!然后根据我的偏好,使用以下语句:

mvdrupal-8.0-alpha13drupal8
sudoln-s/home/firehare/sites/drupal8//var/www/drupal8

其中 /home/firehare是我的用户目录。

3、配置Apache2虚拟主机

接下来就是配置Apache的虚拟主机了

sudovi/etc/apache2/sites-available/drupal8.conf

内容如下所示

<VirtualHost*:80>
ServerNamedrupal8.firehare.me
ServerAdminubuntu.firehare@gmail.com
DocumentRoot"/var/www/drupal8"
<Directory"/var/www/drupal8">
OptionsFollowSymLinks
AllowOverrideAll
ErrorLog"/var/log/apache2/firehare_d8_errors.log"
CustomLog"/var/log/apache2/firehare_d8_accesses.log"common

然后启用虚拟机和覆写模块,并重启Apache2服务,让配置生效。

sudoa2ensitedrupal8
sudoa2enmodrewrite
sudoserviceapache2restart

4、设置DNS服务

在DNS域名服务器中添加drupal8.firehare

阅读更多内容

2014年7月29日星期二

Hibernate对JPA的实现 - 裴东辉

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Hibernate对JPA的实现 - 裴东辉  阅读原文»

/**
* Hibernate对JPA的实现:
* 1、配置Domain
* @Entity
@Table(name = "t_accountinfo")
public class AccountInfo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column(name="balance")
private double balance;
2、配置持久化文件新建文件位置:/src/META-INF/persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
version="2.0">
<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>cn.dh.spring.data.jpa.domain.AccountInfo</class>
<properties>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/springdatajpa" />
<property name="hibernate.connection.username" value="springdatajpa" />
<property name="hibernate.connection.password" value="springdatajpa" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="false" />
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>
</persistence-unit>
</persistence>
3、实现DAO
public class UserDAOImpl implements UserDAO {
private EntityManagerFactory emf;
public UserDAOImpl(){
emf = Persistence.createEntityManagerFactory("default");
}
@Override
public AccountInfo save(AccountInfo accountInfo) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(accountInfo);
em.getTransaction().commit();
emf.close();
return accountInfo;
}
4、对JPA进行测试:
UserDAO userDAO=new UserDAOJAPImpl();
AccountInfo ai=new AccountInfo();
ai.setBalance(100.25);
userDAO.save(ai);
* <p>User: 裴东辉
* <p>Date: 2014-7-29 下午9:21:00
* <p>Version: 1.0
*/

  

项目最小jar包依赖:

db-mysql-connector-java-5.1.8-bin.jar
hibernate-commons-annotations-4.0.4.Final.jar
hibernate-core-4.3.0.Final.jar
hibernate-entitymanager-4.3.0.Final.jar
hibernate-jpa-2.1-api-1.0.0.Final.jar
hibernate-zdp-antlr-2.7.6.jar
hibernate-zdp-dom4j-1.6.1.jar
hibernate-zdp-jandex-1.1.0.Final.jar
hibernate-zdp-javassist-3.18.1-GA.jar
hibernate-zdp-jboss-logging-3.1.3.GA.jar
hibernate-zdp-jboss-transaction-api_1.2_spec-1.0.0.Final.jar

jar包获取,在Spring官网,springproject,spring-data,spring-data-jpa里面找到spring-data-jpa-examples的链接:

https://github.com/spring-projects/spring-data-jpa-examples


本文链接:Hibernate对JPA的实现,转载请注明。

替换变量&和&& - iVictor  阅读原文»

替换变量可看作是占位符

一、 单个&符号替换

SQL语句中最基本、最普遍元素替换形式是单个&符号替换。&符号是用来在语句中指定替换变量的符号。当执行语句时,Oracle服务器处理语句,发现替换变量,并尝试用下面两种方法之一来解析变量的值。首先,它检查在用户会话中是否定义了该变量(DEFINE命令)。倘若没有,用户进程会提示输入一个值,这个值会替换变量。

如下所示:

SQL> select ename,sal from emp where empno=&number;
Enter value
for number: 7934
old
1: select ename,sal from emp where empno=&number
new
1: select ename,sal from emp where empno=7934

ENAME SAL
---------- ----------
MILLER 1300

二、&&符号替换

倘若在多次查询中用到同一替换变量,且该替换变量的值不变,可用&&替换。当oracle服务器遇到&&替换变量时,用进程会提示输入一个值,该值即为该变量的会话值,当后续查询引用该替换变量时,会直接替换为该变量会话值,用户进程不再提示输入值。

如下所示:

SQL> select ename,sal from emp where empno=&&number; -->> 注意,&&符号替换,第一次出现,会提示输入值
Enter value
for number: 7934 -->> 输入值
old
1: select ename,sal from emp where empno=&&number
new
1: select ename,sal from emp where empno=7934

ENAME SAL
---------- ----------
MILLER 1300

SQL
> select ename,sal from emp where empno=&number; -->> 直接引用,不再提示输入新值
old
1: select ename,sal from emp where empno=&number
new
1: select ename,sal from emp where empno=7934

ENAME SAL
---------- ----------
MILLER 1300

SQL
> select ename,sal from emp where empno=&&number; -->> 第二次出现,同样不再提示输入值,number在整个会话期间始终有效
old
1: select ename,sal from emp where empno=&&number
new
1: select ename,sal from emp where empno=7934

ENAME SAL
---------- ----------
MILLER 1300

三、替换列名

上述替代变量替代的基本上是where子句中的元素,但实际上SQL语句中的任何元素都是可以替换的对象。如下所示,第三列被替换:

SQL> select empno,ename,&&col from emp order by &col; -->> 第三列即为替换变量
Enter value
for col: sal -->> 在这里,我们既可以选sal,也可以选择hiredate
old
1: select empno,ename,&&col from emp order by &col
new
1: select empno,ename,sal from emp order by sal

EMPNO ENAME SAL
----- ---------- ----------
7369 SMITH 800
7900 JAMES 950
7876 ADAMS 1100
7521 WARD 1250
...

四、 替换表达式和文本

在运行时几乎可以替换SQL语句的任何元素。条件是Oracle要求至少第一个单词是静态的。在SELECT语句中,至少需要SELECT关键字不变,如下所示:

SQL> select &rest_of_statements;
Enter value
for rest_of_statements: ename from emp where empno=7839
old
1:

2014年7月28日星期一

ASP.NET 如何做出简单的验证码 - 我不会抽烟Oscar

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
ASP.NET 如何做出简单的验证码 - 我不会抽烟Oscar  阅读原文»

如果说要做验证码,那不得不提的就是GDI+绘图了。我们都知道验证码是以图片形式展示的,而且是动态生成的,这样就需要我们去画出它。

科普一下,什么是GDI+?

GDI+是图形设备接口(GDI)的高级版本, 提供了各种丰富的图形图像处理功能。GDI+主要由二维矢量图形、图像处理和版式3部分组成。GDI+为使用各种字体、字号和样式来显示文本这种复杂任务提供了大量的支持。

下面说说验证码,对于验证码这样的图片,我觉得是由两部分组成的,一部分是矩形的背景,另一部分是在其上的字母数字组合(有的时候有汉字,有的时候是纯字母或者纯数字,这个没有统一规定,怎么选择看你~)。对于矩形的背景我们可以直接把其当成画布,字母数字组合呢?我们可以利用随机数去拼出一组新组合。这样整个过程我们都想好了,下面看下代码吧:

声明一下,我写的这个验证码为5个字符长度,由大小写英文字母+数字随机组合。

private readonly char[] constant = {
'0','1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};//一个由数字和大小写英文字母组成的字符数组

protected void Page_Load(object sender, EventArgs e)
{
Bitmap bitmap = new Bitmap(100, 25);//创建一个位图,宽100,高25,就是我所说的第一部分,矩形背景
Graphics g = Graphics.FromImage(bitmap);//创建画布
g.Clear(Color.YellowGreen);//为画布填充黄绿色

Font font1 = new Font("Arial", 15);//设置字体类型和大小
Brush brush = new SolidBrush(Color.Blue);//设置画刷颜色
Pen myPen = new Pen(Color.Blue, 5);//创建画笔对象

StringBuilder random = new StringBuilder(5); //创建可变字符串对象,用于存放随机生成的验证码
Random rd = new Random();//创建一个随机数生成器对象
for (int i = 0; i < random.Capacity; i++)
{
random.Append(constant[rd.Next(62)]);//生成一个随机字符加到random里
}

g.DrawString(random.ToString(), font1, brush, 10, 5);//在画布上画出字符串

System.IO.MemoryStream ms = new System.IO.MemoryStream();//创建数据流MemoryStream
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);//指定图像的输出格式为gif

Response.ClearContent();
Response.ContentType = "image/Gif";
Response.BinaryWrite(ms.ToArray());//输出二进制数据流
}

生成的效果是这样的:

大家可能会觉得这样看起来很容易辨识,跟我们平时登录网站时输入的验证码比起来有点像个小学生。当然,我们可以做些改变,比较加上一定的角度。

private readonly char[] constant = {
'0','1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};//一个由数字和大小写英文字母组成的字符数组

protected void Page_Load(object sender, EventArgs e)
{
Bitmap bitmap = new Bitmap(100, 25);//创建一个位图,宽100,高25,就是我所说的第一部分,矩形背景
Graphics g = Graphics.FromImage(bitmap);//创建画布
g.Clear(Color.YellowGreen);//为画布填充黄绿色

Font font1 = new Font("Arial", 15);//设置字体类型和大小
float angle = 60;//旋转的一个基础角度
float length = 0;//显示字符的基础位置,往后看
Brush brush = new SolidBrush(Color.Blue);//设置画刷颜色
Pen myPen = new Pen(Color.Blue, 5);//创建画笔对象

StringBuilder random = new StringBuilder(5); //创建可变字符串对象,用于存放随机生成的验证码
Random rd = new Random();//创建一个随机数生成器对象
for (int i = 0; i < random.Capacity; i++)
{
random.Append(constant[rd.Next(62)]);//生成一个随机字符加到random里

g.ResetTransform();//将画布重置矩阵
SizeF size = g.MeasureString(random[random.Length - 1].ToString(), font1);//得到新生成字符的尺寸
g.TranslateTransform(length + size.Width / 2, size.Height / 2);//选择此次旋转的中心位置
g.RotateTransform((float)rd.NextDouble() * angle * 2 - angle);//进行随机角度旋转
地球人找工作之番外篇 - 倾剑飞血  阅读原文»

地球人找工作系列是本人去年毕业时,为本校学弟学妹们总结的一点求职心得。转眼一年了,很多人通过本文获得了帮助,所以今天拿出来与更多的朋友来分享。

地球人找工作1之前期准备:http://www.cnblogs.com/jacklandrin/p/3866454.html

地球人找工作2简历的秘密:http://www.cnblogs.com/jacklandrin/p/3870159.html
地球人找工作3笔霸传奇:http://www.cnblogs.com/jacklandrin/p/3870982.html

地球人找工作4面试风云:http://www.cnblogs.com/jacklandrin/p/3872442.html

本篇文章将是地球人找工作系列的最后一篇,作为对其他注意事项和技巧的介绍,也为之前忽略的一些问题作为补充。

  • 择业观

择业观从顺序上来讲,其实应该放在第一篇文章去讲,但是觉得刚上来讲这个东西不太会受到关注,大家应该还是更喜欢看一些实实在在的“干货”。但是刚你真的 用心看完前面几篇文章之后,有些人也许会思考一些问题,我真的适合去干技术吗。专业对不对口问题说实在的是老生常谈了,我个人觉得我自己很幸运的选择了一 个自己了解并且喜欢的专业,并从事了相关的工作,但是很大一部分人是被学了计算机的,他们仍然为自己是否还要从事相关的专业犹豫迷茫着。

我很欣赏超哥曾经说的一句话,“每个人都是有天赋的。”,每个人都有适合自己的工作,如果你喜欢并且擅长一种技能,那么这项技能就是你的天赋,你如果从事这方面的工作,在付出同等的努力下,可能会比那些没有天赋的人做的更好,而且你会很享受你的工作。

因此,在选择职业时,或者更具体为选择你所从事的工作内容时,最优的选择是遵循三个条件:

  1. 适合你的工作
  2. 社会需要的工作
  3. 你喜欢的工作

首先,从各方面评估权衡,这项工作最好是适合你的,不适合的工作是很难被承担的,比如让一个身体瘦弱的女生去当搬砖盖楼的建筑工人,显然是不怎么适合的; 再如招聘ios程序员往往是需要相关经验的,如果他之前只搞过python,连其他的手机客户端也没开发过,显然也是不适合的。无论从外在的客观条件,还 是内在的技术经验,适合应该是第一位的。

然后,我们需要考虑适合我们的这些工作中,哪些是社会比较需要的,一般越需要的工作,机会就越多。这反过来也告诉我们,尽量学一些社会所急需的知识和技 能。我小学时,看过一个小故事,叫《学杀龙》,故事的主人公为了能在故乡出人头地,于是背井离乡外出学艺,几年后学成归来,当着全村人的面舞刀弄剑,表演 他的杀龙技法,但看完他的表演后,大家只是随便笑了笑,就都转身离开了,而他并没有受到村里人的敬仰,而成为了村中的笑柄,他不解的去问村中的老者,这是 为什么,老者说:“这世界上根本就没有龙,你学的杀龙的技法根本没有任何用处啊。”这个故事告诉了我们,择业之前必须认清需求。

最后就是,你所干的工作最好是你喜欢的,有人可能会问这是不是跟第一点重复了,其实不然。有人可能很擅长去做一项工作,但是却不一定能从中得到快乐。就好 比你打字打的又准又快,但是你不一定喜欢去做一名打字员一样。我们的工作是为了生活,生活要生活的快乐,没有人会去刻意的追求痛苦,所以去做自己喜欢的事 情吧,不要让工作成为生活的负担,即使这种工作给你带来大量的财富,人不能穷的就省钱了。很多人盲目的攀比和追逐,实际上他们根本不清楚什么是自己所想要 的,所以在争取金钱和名利的同时,也奉劝大家思考一下,这是不是自己想要的生活。

  • 择业态度

当你从上面三个条件中权衡出自己目标的职业时,就马上为之努力吧。择业中我们必须要抱有积极的态度,事实上如果你确实已经认认真真的思考三个条件之后,它 们就已经帮助你消除了很多消极的烦恼。所以,千万不要在大四下半学期没有找到工作的情况下,还整天在宿舍里打电脑游戏,最后在家里闲了一年之后找一个自己 也不相干,又累还不挣钱的工作,那时的你只剩下向同事或者街坊四邻整天抱怨社会的本事了。如果对自己的人生负责的话,就认认真真的对待它吧。

我个人在大四求职的道路上受过很多挫折,被拒过,被悔过,5月的时候工作还没有着落,但是我会总结经验,并且调动我所能够调动的资源来帮助我求职。只要有 信念在,方法和机会总是有的。我周围还有很多同学,他们没有什么项目和实习经验,但是他们有信念和目标,没有技术,他们去参加培训班,没有正式 offer,可以找实习单位先干着,这些都要比坐以待毙强的多。

  • 关于前期准备的补充

有 些人有端正的择业态度,但是缺乏方法。其实我之前几篇文章着重突出的就是经验与方法,这里在前期准备中需要补充的一点就是,学会统计、分析与总结。你可以 列一张表格,把提供给适合你岗位的企业做一个统计,尽可能的搜索企业和此岗位的相关信息,然后加以比对,这里面分智网是我十分推荐的网站,里面提供了许多 企业的相关信息,包括岗位薪资等大家比较关注的问题。建议将你之前听说过的企业和没听说过名字的企业分来进行分析,一般你听说过名字的企业应该都比较 nb,很容易干扰你对其他企业的评估结果,没听过名字的企业中肯定也不乏nb的企业,只是你之前没有去了解。当你掌握这些企业的一手资料之后,有时会颠覆 一下三观,使你会产生对企业新的认识,这种认识会给你对公司的选择和求职面试带来许多帮助。

  • 关于面试的补充

面试方面补充两点,称谓和诚实。

面试时,为了保证互相尊重,需要注意称谓的使用,一般需要用敬语“您”作为第二人称代词,如果你不知道面试官的职位,一般就称之为经理。然后就是,尽可能 用亲近的称谓,比如不要对你应聘的公司称为“贵公司”,你不是谈生意去的,最好用“咱们公司”来替代,显得比较亲近。

然后就是诚实,在面试时,千万不要撒谎,尤其是重要的一些信息。你可以避轻就重,但不要夸大其词。否则,如果你入职之后,你的谎言被拆穿之后,你的信誉度会受到沉重的打击。

  • 关于内推

现在大多数的企业都有内推制度,就是公司内部的工作人员推荐你应聘某个岗位,有的内推可以免除笔试,会让用人方优先考虑你。而作为推荐人的好处是,假如推荐成功,会有几千元的奖金。所以内推是一种互赢互利的招聘方式,但是这里需要注意几点。

第一,推荐人最好和你应聘的岗位在同一部门,或者跟这个部门的人很熟。

第二,滥竽充数可是过不了面试的,部门的管理人员会深入考察你是否有真才实学的,别给推荐人丢脸。

第三,推荐成功之后,你别最后不来这家公司,弄得大家都不合适。

  • 关于选择

选择本身是一个烦恼,校招季有的人可能一个offer都没拿到,有的人拿了好几个。有人可能一周内就要给用人方回复接不接offer,而另一个企业的 offer还没下来。有时选择会有一些运气的成分在里面,但是更重要的是人心,你需要清楚什么是你想要的,根据自己的内心去做选择,摒弃外界的一切干扰, 放下烦躁与紧迫感,想想哪个工作更有发展,哪个工作更适合自己,回到你最原始的原则上来。

这里还要说的一点时,选择要尽早的下决定, 不要拖拖拉拉,最后让对方去毁约,因为一般应聘者接offer的比率是30%,也就是说校招中一个岗位招30人,他可能会发100个offer,尤其像搜 狐、美团这样的大公司。如果秋季给你发了offer,春季的实习你没来,当实习的报道数超过他计划招生时,他是有可能毁约的。所以,在抉择上,你要尽早抉 择,尽早回复,如果有实习的话,尽早过去实习。

好了,地球人找工作系列到这了就此就结束了,希望这会对即将面临找工作的学弟学妹们有所帮助,有什么疑问的话可以联系我或者给我留言,其中说的不对的一些地方,也请批评指正。最后,祝学弟学妹们都能找到一个满意理想的工作!


本文链接:地球人找工作之番外篇,转载请注明。

阅读更多内容

最近架构随想

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
最近架构随想  阅读原文»

最近架构随想

今天新加坡放假,闲来无事就发一篇博客:一则总结归纳项目构架经验,审视并逐步提高自 己;再者分享最近学习所得,希望各位能讨论并给些建议。六月三十日从原来公司离职,七月一日入职新公司,不知不觉已经快一个月了。最近忙于学习新的行业知 识以及项目的重构设计,没有时间发博客,也没有时间回复邮件及博文评论,忘各位见谅!

今天发几张项目重构设计草图,如果大家对项目分层与文件夹结构比较感兴趣,可以参考几年前弦哥.Net项目分层与文件夹结构大全(最佳架子奖,吐槽奖,阴沟翻船奖揭晓),这次的架构方案基本是之前架构经验第一次在保险行业的使用,希望各位能积极探讨并给些意见!

根据个人经验,架构决定项目的成败以及高度,所以在编码之前一定要设计好项目的整体规划和架构。好的架构或者考虑比较全面到位的架构会极大的帮助团队,对项目起到灵魂的作用;糟糕的设计往往会把整个项目组带入泥潭或者恶性循环,对项目直接致命打击!

回归正题:

  • 整个架构分为Online(Web Application)和Offline(WPF Application)两部分。

  • Online(Web Application)需要支持不同的设备及浏览器,所以采用Bootstrap和 ASP.NET MVC with Razor作为View,KnockoutJs作为MVVM框架。UI Designer设计好UI,然后由前端工程师绑定相应的UI Model到UI,后端工程师则负责相应的OOAD以及业务处理。

  • Offline(WPF Application)需要在没有网络的情况下能正常工作,所以采用WPF XALM作为View,MVVM Light作为MVVM框架。UI和后端的处理以及任务分配和Online(Web Application)基本一致。

  • Services :设置了Switch功能,可以配置是否使用WCF或者Web API或者直接调用Dll。

  • Domain Model:始终是应用程序的核心,必须投入大量精力,按照面向对象的分析和设计 (OOAD) 进行设计同时按照OOP进行开发。

  • Infrastructure:主要包括数据访问组件、通用权限框架、异常和日志处理组件、IOC/AOP功能、缓存机制,邮件,配置等基础或常用功能。

  • 行业知识:由于项目牵涉到具体的行业(保险业),所以在业务流程中创建了Insurance Engine,专门处理保险相关的基础功能。

  • 权限系统:由于整个项目比较庞大,再加上其他系统也需要用到同样的权限判断,所以创建了一个新的权限数据库,用来存储及处理权限相关的所有数据及规则,所有用户则来源于三个数据源(SQL Server, DB2和Active Directory)。

  • Unit Test:每一层都有单独的单元测试,方便项目功能自测,维护,重构,升级以及管理。28-7-2014 12-31-12 AM

组件之间的详细关系如下:

28-7-2014 12-27-11 AM

各层之间的执行顺序如下:

28-7-2014 12-34-29 AM

  • 用户来源于三个数据源(SQL Server, DB2和Active Directory)。

  • 现实世界和系统通过角色进行关联,现实世界的用户及组的变化尽量不要影响到系统。

  • 一个用户可以有多个角色,一个角色也分配给多个用户。

  • 权限分为功能权限和数据权限。

  • 权限系统要提供给几套系统使用,全部的接口通过Service的形式提供出来。

security

由于时间有限,设计可能存在诸多不足之处,如果大家有不同的意见或者建议,不妨在评论中指出,以便互相学习且共同提高!

本文出自 "圣殿骑士" 博客,请务必保留此出处http://knightswarrior.blog.51cto.com/1792698/1531155

返回顶部

分析演示: RIP动态路由协议引发的HSRP收敛问题  阅读原文»

  • 本周内更新

分析演示: RIP动态路由协议引发的HSRP收敛问题

演示目标:

1 动态路由协议在某种程度上可以帮助HSRP收敛无跟踪的盲点

2 动态路由协议RIP可能引发HSRP收敛的问题

3 为什么同一子网的主机,有些收敛快,有些慢?

演示环境:1所示的环境

背景说明:从实践的角度来讲,在需要部署HSRP进行三层冗余的环境中,通常物理链路也是成环的,那么这种环境中,进行网络设计时需要特别注意动态路由协议的选择,以及评估和预测可能引发的各种收敛问题,明确到底是HSRP在为用户网络在实现冗余,还是三层的动态路由协议在为用户实现冗余,如果发生收敛问题,比如:收敛慢,是什么原因导致问题的发生,以及如何对这些问题进行修复。

wKioL1PVrzrRSlrdAAHW20eTNFk295.jpg

演示步骤:

第一步:在如1所示的网络环境中为所有的三层设备启动RIPv2的动态路由协议,具体配置如下所示,确保各个路由器的动态路由学习正常,这是整个演示环境的基础保障。

路由器R1RIP配置:

R1(config)#routerrip

R1(config-router)#noauto-summary

R1(config-router)#version2

R1(config-router)#network 192.168.1.0

R1(config-router)#network 192.168.4.0

R1(config-router)#network 172.16.0.0

R1(config-router)#exit

路由器R2RIP配置

R2(config)#routerrip

R2(config-router)#version2

R2(config-router)#noauto-summary

R2(config-router)#network 192.168.2.0

R2(config-router)#network 172.16.0.0

R2(config-router)#exit

路由器R3RIP配置:

R3(config)#routerrip

R3(config-router)#version2

R3(config-router)#noauto-summary

R3(config-router)#network 192.168.1.0

R3(config-router)#network 192.168.4.0

R3(config-router)#network 192.168.2.0

R3(config-router)#network 30.30.30.0

R3(config-router)#exit

完成上述配置后路由器R1的路由器表如2所示。

wKioL1PVr22QG1RCAAPOR7yXGv8972.jpg

注意:R1的路由表中有一条暂时没有显示,被隐藏的到 30.30.30.0RIP路由,这条路由器R1通过下一跳是R2172.16.1.2来到达30.30.30.0的路由,它为什么会被隐藏,因为RIP以跳数来评估路由的度量,通过192.168.4.3192.168.1.31跳,而经过R2172.16.1.2来到达30.30.30.0的路由是2跳,所以它暂时被隐藏,那么在一种情况下该路由器会出现,那就是下一跳192.168.4.3192.168.1.3这两条路由失效时,到此为后面的问题做出了预设。

现在将路由器R1R2E1/0接口规划到HSRP热容组1,虚拟IP地址是172.16.1.254,要求R1为活动路由器,并配置两台路由器的抢占功能,具体配置如下所示:

注意:暂时不去配置任何接口跟踪!

路由器R1HSRP配置:

interface Ethernet1/0

ipaddress 172.16.1.1 255.255.255.0

standby1 ip 172.16.1.254 * 配置HSRP的虚拟IP地址

standby 1 priority 110 * 配置优先级为110,确保R1HSRP组中的活动路由器

standby 1 preempt * 配置抢占功能

路由器R2HSRP配置:

interface Ethernet1/0

ipaddress 172.16.1.2 255.255.255.0

standby 1 ip 172.16.1.254

standby 1 preempt

为什么不为R2配置优先级?

默认优先级为100,为了确保能让R1(优先级110)成为活动路由器,所以没必要去配置R2的优先级,使用保持默认的100

提出一个问题:现在到第一步的配置为止,如果路由器的S2/0E1/1端口出现故障,请问HSRP的活动路由器是否会从R1切换到R2,流量是否会被R2所接管,在主机上能否成功的ping30.30.30.1?

第二步:在路由器R1上制造故障去shutdown路由器R1S2/0E1/1接口

R1(config)#intes2/0

R1(config-if)#shutdown *关闭S2/0

R1(config-if)#exit

R1(config)#intee1/1

R1(config-if)#shutdown *关闭E1/1

R1(config-if)#exit

系统提示:两个接口的管理属性为down

*Jul 24 11:24:11.047: %LINK-5-CHANGED: InterfaceSerial2/0, changed state to administratively down

*Jul 24 11:24:11.055: %LINEPROTO-5-UPDOWN: Lineprotocol on Interface Serial2/0, changed state to down

wKioL1PVr7uTboZbAAKCCuqiqLA436.jpg

阅读更多内容

2014年7月26日星期六

Socket网络编程--聊天程序(4) - 无脑仔的小明

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Socket网络编程--聊天程序(4) - 无脑仔的小明  阅读原文»

  上一小节讲到可以实现多客户端与服务器进行通讯,对于每一个客户端的连接请求,服务器都要分配一个进程进行处理。对于多用户连接时,服务器会受不了的,而且还很消耗资源。据说有个select函数可以用,好像还很NB的样子。

  使用select多路转换处理聊天程序

  下面摘取APUE 14.5小结 I/O多路转接

当从一个描述符读,然后又写到另一个描述符时,可以在下列形式的循环中循环中使用阻塞I/O:

  while((n = read(STDIN_FILENO, buf, BUFFSIZ))>0)

    if(write(STDOUT_FILENO, buf, n)!=n)

      err_sys("write error");

这种形式的阻塞I/O到处可见。但是如果必须从两个描述符读,又将如何呢?如果仍旧使用阻塞I/O,那么就可能长时间阻塞在一个描述符上,而另一个描述符虽有很多数据却不能得到及时处理。所以为了处理这种情况显然需要另一种不同的技术。

方法一:也就是上一小节使用的方法,使用多进程。每一个进程处理一个描述符

方法二:和上面相似的,使用多线程,不同的线程处理不同的描述符

方法三:仍然使用一个进程执行该程序,但使用非阻塞I/O读取数据。然后对所有的描述符进行遍历一遍,判断对应的描述符是否有数据,如果有就读取,如果没有就立即返回。这种办法就是轮询(polling)

方法四:异步I/O。其基本的思想是进程告诉内核,当一个描述符已经准备好可以进行I/O时,用一个信号通知它。

方法五:这是一种比较好的办法。叫做I/O多路转换(I/O multiplexing)。先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已经准备好进行I/O时,该函数才会返回。在返回时,它高数进程哪些描述符已经准备好可以进行I/O。

  poll,pselect和select这三个函数使我们能够执行I/O多路转换。本程序只使用select函数。

  #include <sys/select.h>

  int select (int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds, struct time val *restrict tvptr); //返回值:准备就绪的描述符数,若超时则返回0,否则出错返回-1

  select 函数讲解
  FD_ISSET判断描述符fd是否在给定的描述符集fdset中,通常配合select函数使用,由于select函数成功返回时会将未准备好的描述符位清零。通常我们使用FD_ISSET是为了检查在select函数返回后,某个描述符是否准备好,以便进行接下来的处理操作。

  fd_set数据类型的操作

  #include <sys/select.h>

  int FD_ISSET(int fd, fd_set *fdset);  //判断fd是否在fdset中

  void FD_CLR(int fd, fd_set *fdset);  //进fd从fdset中取出

  void FD_SET(int fd, fd_set *fdset);  //将fd放入fdset

  void FD_ZERO(fd_set *fdset);    //将fdset清空

  timeval结构分析

  struct timeval{

    long tv_sec; //seconds

    long tv_usec; //and microseconds

  };

  client.c的代码没有改

  server.c的代码如下

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <netdb.h>
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <sys/time.h>
9 #include <sys/un.h>
10 #include <sys/ioctl.h>
11 #include <sys/wait.h>
12 #include <sys/select.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15
16 #define SERVER_PORT 12138
17 #define BACKLOG 20
18 #define MAX_CON_NO 10
19 #define MAX_DATA_SIZE 4096
20
21 int MAX(int a,int b)
22 {
23 if(a>b) return a;
24 return b;
25 }
26
27 int main(int argc,char *argv[])
28 {
29 struct sockaddr_in serverSockaddr,clientSockaddr;
30 char sendBuf[MAX_DATA_SIZE],recvBuf[MAX_DATA_SIZE];
31 int sendSize,recvSize;
32 int sockfd,clientfd;
33 fd_set servfd,recvfd;//用于select处理用的
34 int fd_A;//保存客户端的socket描述符
35 int conn_amount;//用于计算客户端的个数
36 int max_servfd,max_recvfd;
37 int on=1;
38 socklen_t sinSize=0;
39 char username[32];
40 int pid;
41 int i;
42 struct timeval timeout;
43
44 if(argc != 2)
45 {
46 printf("usage: ./server \n");
47 exit(1);
48 }
49 strcpy(username,argv[1]);
50 printf("username:%s\n",username);
51
52 /*establish a socket*/
53 if((sockfd = socket(AF_INET,SOCK_STREAM,0))==-1)
54 {
55 perror("fail to establish a socket"ENC28J60 + M430G2553,用uip搭建http服务器,解决"在XP系统下可以访问,在Win7下不能访问"的问题 - Gizmo.G  阅读原文»

近日,用ENC28J60,在M430G2553上搭建一个简单的HTTP服务器,结果发现在XP系统下可以访问,在Win7下不能访问,非常奇葩的问题。

通过抓包,如下图,计算机(IP地址为192.168.1.104)给服务器(IP地址为:192.168.1.150)发动的TCP包中的不添加Checksum信息。

上述问题,导致在uip中直接丢弃此TCP包,如下图。

为了适应默认的Win7系统设置,只能修改uip,让其不做Checksum,把上图的过程注释掉即可。


本文链接:ENC28J60 + M430G2553,用uip搭建http服务器,解决"在XP系统下可以访问,在Win7下不能访问"的问题,转载请注明。

阅读更多内容

2014年7月24日星期四

写给新入职的毕业生们

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
写给新入职的毕业生们  阅读原文»

写给新入职的毕业生们

今天,我作为"前辈"给公司新入职的应届毕业生们做了一次经验分享,简单整理了一下演讲的内容,希望对其他人也能有所帮助。

1.进入公司与校园有什么不同 ?

作为一个技术型的公司,其实公司内部的办公环境与在学校实验室没有太大的区别,每个人都有自己的位置,大家各司其职,为公司的项目贡献自己的代码,偶尔跟学长/学姐们一起调试问题,一起解决Bug,项目空档期还可以看看书,学习提高……

如果非要说有什么不同,我想更多的是在生活方面吧。

大家背井离乡,独自来到上海,第一个要面对的社会问题就是租房子了,可能会遇到一个黑心的中介,也可能会遇到一个恶心的房东,无论你是吃亏了也好,还是被骗了也好,请坦然面对,因为离开校园以后的人生路上,你还会遇到更多更多的麻烦事,遇到更多更多的"坏人",学着在每一次吃亏上当中总结经验教训,总有一天,你会强大起来,不再让父母在遥远的家乡继续为你操心。

第二个或许会面对的问题,就是下班后的孤独感,如果跟你一起来上海工作的朋友比较少的话,这种感触或许会更深。住了4~7年的学生宿舍,习惯了每天晚上回到寝室侃大山,习惯了有一群哥们陪你打游戏,甚至习惯了偶尔能跟室友绊个嘴闹点小矛盾,如今,每天回到住处,面对的是空空如也的房间,你必须得适应这样的生活,当然,你也可以选择每天加班到很晚再回去,不过我建议最好的办法就是赶紧找到另一半吧。

第三个就是你会发现如今的生活变得非常有规律了,刚刚习惯了大学生活的丰富多彩,一下子又回到的高中时代的两点一线,周一到周五,不会再有任何新鲜感,甚至连锻炼身体的时间都没有了,我就是从工作到现在已经涨了12斤了。希望大家不要学我,一定要有自己的锻炼计划,比如每周打几次篮球、晚上去跑跑步,或者健身、游泳,什么都好,身体是革命的本钱,虽然年轻,但一定要好好爱惜。

第四个就是有工资了,这可是一个质的飞跃,自此以后,你再也不用伸手向父母索要生活费了,还可以反过来买点东西孝敬孝敬他们;你终于可以买喜欢的礼物送给心爱的他/她了;你也可以经常去餐馆吃顿大餐,或者买几件贵点的衣裳,而不用担心后半个月天天只有啃馒头度日了……

当然,你肯定会体验到更多的不同,这里我也不一一赘述了,希望大家能早日适应离开校园步入职场以后的生活。

2. 我的经验和建议

下面进入正题,我将从技术的角度,给大家讲讲我在公司这一年多以来收获的经验和教训。

2.1 让自己的工作更加"专业"

现在你已经成为公司的一名正式的员工了,你所开发的产品可能会直接投入到市场,会面对客户,因此,再也不要像在实验室做研究那样随随便便了,你要时刻为自己的工作负责,要想得到老板和客户的赏识,你就必须表现得足够的专业。

(1) 提交代码之前请充分测试

公司的产品可能需要很多部门的通力合作,你的代码指不定哪一天会被应用到一个重量级的产品上面,请不要留有Bug,一旦经过复杂的集成之后,再去定位和修改你的代码通常会是一件非常耗时耗力的事情。

(2) 保持"封装"意识

"封装"有无数的好处,可以让程序的结构更加清晰,可以在其他项目中重复利用,方便调试和定位问题,带来更好地可替换性和可移植性,不要因为偷懒或者赶进度就放弃模块化,良好的代码结构会给项目带来无尽的好处。

(3) 关心性能和效率

关注性能和效率并不仅仅是算法开发人员的专利,每一个程序员都要有这种意识,你要时刻做好准备被提问以下这几个问题:

你的算法执行时间是多久? 你的程序占用内存多大? CPU占用率呢?

能够第一时间回答老板或者客户关于性能的提问,会让你显得非常地专业,同时,性能的测试往往能够帮助你找到很多隐藏的Bug,很多次,我都是在关注系统内存占用曲线图的时候发现一些内存泄露并且解决掉的。

(4) 版本控制

客户的需求总是不断改变的,你刚刚开发好的功能今天客户说不要了,说不定明天他又会需要,所以保持一个良好的版本控制记录,会让你的工作游刃有余,谁都不喜欢把做过的事情删除掉然后重新再做一遍的感觉。

当然,版本控制还有另外一个好处就是协助你定位Bug,一旦遇到问题,你总是能够通过版本回滚找到没有该问题的版本,并通过对比找到问题所在。

有很多工具可以帮助我们进行版本控制,如Git,Svn,当然哪怕是使用最原始的建立N多个文件夹的方式也总比没有版本控制的好。

(5) 写出"专业级"的代码

什么是专业的代码?我们评价一份代码专业不专业并不仅仅是看它是否实现了所需的各项功能,而更多的是体现在代码的命名、结构、注释、内存管理等等一系列的地方。

举个例子吧,你们扪心自问一下,在你们做过的项目中,是不是确保了每一个申请的资源都正常释放了?是不是通过Join等待过每一个线程的退出?Socket的阻塞是否真正地唤醒了?有没有代码修改了注释却忘记修改的时候?

真正优秀的程序员,并不是指他们写出的程序没有Bug,而是他们在写程序的时候,会考虑得更加全面和仔细,去避免一些不必要的Bug出现。

2.2 原创和版权意识

我记得有人说过,你要实现的大部分技术或者功能,你都不会是第一个做的,也不会是最后一个做的。所以,在接手一项不熟悉的任务的时候,我们通常都会去Google/Baidu上搜索一下,看看有没有类似的案例,看看有没有别人写好的代码。

的确,网上别人的代码的确可以帮助我们快速地实现一些功能,但是你要时刻注意,网上的代码,尤其是一些国内博客中给出的代码,经常写得非常地不严谨,你在使用它们之前,一定要充分地理解和消化,解决掉其中隐含的Bug,最好能够用自己的方式实现一遍。不假思索地拿来就用,很可能就在项目中埋下了一个***,随时都有可能会爆炸。

另外,为公司开发产品,一定要注意版权意识,在使用第三方开源代码或者库之前,请仔细阅读License,不要让公司莫名其妙地背上侵权的恶名。

最后我还想说明一下的就是,对自己做的东西,一定不要浮于表面,要深入地理解其原理,不要过于依赖别人的代码或者第三方库,要相信自己,搞清楚了原理,其实你是有这个能力自己去实现这些功能的。

2.3 向你的老板学习

技术人员一般都很自负,很容易否定同行,在学校我深有体会,几乎我认识的每一个研究生都很鄙视自己导师的"技术水平",但是在我们公司,请大家相信,你的老板之所以能够成为你的老板,一定是有他的过人之处的,请虚心向他学习,你一定能收获很多。

这一年多以来,我就从我的老板身上学到了很多很多,除了上面提到的一些感悟以外,简单地再列举几点吧。

(1) 不惧怕任何问题

我一直有个毛病,就是只要是我自己写的代码,一旦出了问题,我有100%的信心找到根源,并且漂亮地解决掉。但是,一旦项目中集成了太多第三方库或者其他人的代码,而且问题在他们那块的时候,我就会不自觉地退缩和抱怨,而老板从来都不会,他总是会跑过来跟我一起耐心地调试,一行行地阅读和分析那些"晦涩"的代码,直到找到问题所在为止。这一点我真的很佩服,老板是整个项目组最后一道屏障,一旦老板都退缩了都放弃了,项目也就黄了,所以,我觉得,这一点是我要走向老板之路必须具备的品质。

(2) 不放过任何一个Bug

项目中的Bug,一旦被我老板知道了,无论是过一天、一周、甚至一个月,他永远都不会忘记,总会时不时过来问问我,那个Bug解决了没有,怎么解决的,具体原因是什么。我想,所有被称之为优秀的产品或许就是由一个个这样执着的老板们造就的吧。

(3) 听从员工的建议

我一直觉得,对于任何一个产品,除了客户,奋斗在第一线的研发人员是最有发言权的,他们会比很多高层领导更加清楚产品的技术细节。我不喜欢开会的时候只有接受任务的义务,而没有发言的权力。所以,我喜欢让我说话的老板,我的老板在这一点就做得真的非常好,很多我的建议都被采纳到了产品的设计中了,这让我非常有成就感。

在一个技术型的公司里,好的老板不是靠官职来压人,而是靠人格魅力来"领导"人。

2.4 拼命去提高你的技术

高中的时候,我们以为考入好大学了就一辈子轻松了,于是我们为了进一个好大学而拼命努力;而到大学了,我们又发现,还是得努力,找到一个好工作就舒坦了,于是我们又奋斗了7年,现在你们成功了,来到了一个好公司,享受着不错的薪水。但是我还是得遗憾地告诉你们,这还不够,我们依然得努力,为了我们能在上海这个城市活得更好。

我们时刻要很清楚我们现在处于一个什么样的人生阶段。

现在的我们,属于职场新人,在这职业生涯的头几年,你还没有成家,还没有小孩,没有太多生活

大话数据中心双活  阅读原文»

大话数据中心双活

投资界有一句至理名言��"不要把鸡蛋放在同一个篮子里"。说的是投资需要分解风险,以免孤注一掷失败之后造成巨大的损失。同样近年来自然灾害的频发为各行业的安全敲醒了警钟,对于IT系统来说如何通过灾备保证系统安全及业务连续性成为广大IT人关注的问题,而双活数据中心则是热门的解决方案。但双活真正能够实现业务的零中断吗?在建立双活之初,又该如何根据自己的实际情况来选择双活的实现方式(数据库双活、应用双活、存储双活、网络双活)?本文就来说一说道一道。

双活数据中心,区别于一个数据中心、一个灾备中心的模式。灾难是一个小概率事件,采用一主一备这种方式,备份数据中心只在灾难发生时才能起到作用,这对于某些用户来说是IT资源和资金的浪费。而双活数据中心的特点是两个数据中心都是在线运行的,如果断了一个数据中心,另外一个数据中心还是在正常运行的,对用户来说是不可感知的,业务几乎不受影响。这样就充分利用了资源,从而避免一个数据中心常年处于闲置状态而造成浪费。并且通过资源整合,"双活"数据中心的服务能力是双倍的。

一、网络双活

从网络上来看,双活数据中心需要将同一个网络扩展到多个数据中心,在数据中心间需要大二层网络连接并且实现服务器和应用的虚拟化数据中心互联技术。大二层的网络技术有IRF、TRILL、SPB、EVI等。IRF是将多台网络设备(成员设备)虚拟化为一台网络设备(虚拟设备),并将这些设备作为单一设备管理和使用。IRF把多台设备合并,简化了管理提高了性能,但IRF构建二层网络时,汇聚交换机最多是可达4台,在二层无阻塞的前提下可接入13824台双网卡的千兆服务器,如果客户期望其服务器资源池可以有效扩充到2万台甚至更大,就需要其他技术提供更大的网络容量;TRILL的全称就是Transparent Interconnection of Lots of Links,顾名思义,其本质就是将很多条链路透明地组织在一起,以致于上层IP应用感觉这只是一条链路似的。它本质上是一个2.5层的技术,使用最短路径、多路径等三层路由技术来讲多条链路组织成为一个大二层网络,并支持VLAN、自配置、多播等二层功能。TRILL目前最大可以支持10核心组网,其最大能力可以无阻塞的接入27648台双网卡千兆服务器,但TRILL技术目前在芯片实现上存在客观缺陷,核心层不能支持三层终结,也就是说TRILL的核心层不能做网关设备。必须要在核心层上再增加一层设备来做网关,这导致网络结构变得复杂,管理难度增加,网络建设、运维成本都会增加;SPB的组网方案和TRILL基本相同(同样可支持接入27648台),其优势在于能够方便的支持VLAN扩展功能,但同样存在网关与SPB核心必须分离的芯片缺陷,导致网络层次增加,管理、运?p>阅读更多内容