日期: 2021 年 9 月 7 日

Android Context 上下文 你必须知道的一切

Android Context 上下文 你必须知道的一切

 

1、Context概念

其实一直想写一篇关于Context的文章,但是又怕技术不如而误人子弟,于是参考了些资料,今天准备整理下写出来,如有不足,请指出,参考资料会在醒目地方标明。

Context,相信不管是*天开发Android,还是开发Android的各种老鸟,对于Context的使用一定不陌生~~你在加载资源、启动一个新的Activity、获取系统服务、获取内部文件(夹)路径、创建View操作时等都需要Context的参与,可见Context的常见性。大家可能会问到底什么是Context,Context字面意思上下文,或者叫做场景,也就是用户与操作系统操作的一个过程,比如你打电话,场景包括电话程序对应的界面,以及隐藏在背后的数据;

但是在程序的角度Context又是什么呢?在程序的角度,我们可以有比较权威的答案,Context是个抽象类,我们可以直接通过看其类结构来说明答案:

%title插图%num

可以看到Activity、Service、Application都是Context的子类;

也就是说,Android系统的角度来理解:Context是一个场景,代表与操作系统的交互的一种过程。从程序的角度上来理解:Context是个抽象类,而Activity、Service、Application等都是该类的一个实现。

在仔细看一下上图:Activity、Service、Application都是继承自ContextWrapper,而ContextWrapper内部会包含一个base context,由这个base context去实现了*大多数的方法。

先扯这么多,有能力了会从别的角度去审视Context,加油~

 

2、Context与ApplicationContext

看了标题,千万不要被误解,ApplicationContext并没有这个类,其实更应该叫做:Activity与Application在作为Context时的区别。嗯,的确是这样的,大家在需要Context的时候,如果是在Activity中,大多直接传个this,当在匿名内部类的时候,因为this不能用,需要写XXXActivity.this,很多哥们会偷懒,直接就来个getApplicationContext。那么大家有没有想过,XXXActivity.this和getApplicationContext的区别呢?

XXXActivity和getApplicationContext返回的肯定不是一个对象,一个是当前Activity的实例,一个是项目的Application的实例。既然区别这么明显,那么各自的使用场景肯定不同,乱使用可能会带来一些问题。

下面开始介绍在使用Context时,需要注意的问题。

 

3、引用的保持

大家在编写一些类时,例如工具类,可能会编写成单例的方式,这些工具类大多需要去访问资源,也就说需要Context的参与。

在这样的情况下,就需要注意Context的引用问题。

例如以下的写法:

  1. package com.mooc.shader.roundimageview;  
  2. import android.content.Context;  
  3. public class CustomManager  
  4. {
  5.     private static CustomManager sInstance;  
  6.     private Context mContext;  
  7.     private CustomManager(Context context)  
  8.     {
  9.         this.mContext = context;  
  10.     }
  11.     public static synchronized CustomManager getInstance(Context context)  
  12.     {
  13.         if (sInstance == null)  
  14.         {
  15.             sInstance = new CustomManager(context);  
  16.         }
  17.         return sInstance;  
  18.     }
  19.     //some methods   
  20.     private void someOtherMethodNeedContext()  
  21.     {
  22.     }
  23. }

对于上述的单例,大家应该都不陌生(请别计较getInstance的效率问题),内部保持了一个Context的引用;

这么写是没有问题的,问题在于,这个Context哪来的我们不能确定,很大的可能性,你在某个Activity里面为了方便,直接传了个this;这样问题就来了,我们的这个类中的sInstance是一个static且强引用的,在其内部引用了一个Activity作为Context,也就是说,我们的这个Activity只要我们的项目活着,就没有办法进行内存回收。而我们的Activity的生命周期肯定没这么长,所以造成了内存泄漏。

那么,我们如何才能避免这样的问题呢?

有人会说,我们可以软引用,嗯,软引用,假如被回收了,你不怕NullPointException么。

把上述代码做下修改:

  1. public static synchronized CustomManager getInstance(Context context)  
  2.     {
  3.         if (sInstance == null)  
  4.         {
  5.             sInstance = new CustomManager(context.getApplicationContext());  
  6.         }
  7.         return sInstance;  
  8.     }

这样,我们就解决了内存泄漏的问题,因为我们引用的是一个ApplicationContext,它的生命周期和我们的单例对象一致。

这样的话,可能有人会说,早说嘛,那我们以后都这么用不就行了,很遗憾的说,不行。上面我们已经说过,Context和Application Context的区别是很大的,也就是说,他们的应用场景(你也可以认为是能力)是不同的,并非所有Activity为Context的场景,Application Context都能搞定。

下面就开始介绍各种Context的应用场景。

 

4、Context的应用场景

%title插图%num

 

大家注意看到有一些NO上添加了一些数字,其实这些从能力上来说是YES,但是为什么说是NO呢?下面一个一个解释:

数字1:启动Activity在这些类中是可以的,但是需要创建一个新的task。一般情况不推荐。

数字2:在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。

数字3:在receiver为null时允许,在4.2或以上的版本中,用于获取黏性广播的当前值。(可以无视)

注:ContentProvider、BroadcastReceiver之所以在上述表格中,是因为在其内部方法中都有一个context用于使用。

 

好了,这里我们看下表格,重点看Activity和Application,可以看到,和UI相关的方法基本都不建议或者不可使用Application,并且,前三个操作基本不可能在Application中出现。实际上,只要把握住一点,凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以,当然了,注意Context引用的持有,防止内存泄漏。

 

5、总结

好了,到此,Context的分析基本完成了,希望大家在以后的使用过程中,能够稍微考虑下,这里使用Activity合适吗?会不会造成内存泄漏?这里传入Application work吗?

由于参考内容过多,本文改为译文咯~~

Android Context完全解析,你所不知道的Context的各种细节

Android Context完全解析,你所不知道的Context的各种细节

 

Context相信所有的Android开发人员基本上每天都在接触,因为它太常见了。但是这并不代表Context没有什么东西好讲的,实际上Context有太多小的细节并不被大家所关注,那么今天我们就来学习一下那些你所不知道的细节。

 

Context类型

我们知道,Android应用都是使用Java语言来编写的,那么大家可以思考一下,一个Android程序和一个Java程序,他们*大的区别在哪里?划分界限又是什么呢?其实简单点分析,Android程序不像Java程序一样,随便创建一个类,写个main()方法就能跑了,而是要有一个完整的Android工程环境,在这个环境下,我们有像Activity、Service、BroadcastReceiver等系统组件,而这些组件并不是像一个普通的Java对象new一下就能创建实例的了,而是要有它们各自的上下文环境,也就是我们这里讨论的Context。可以这样讲,Context是维持Android程序中各组件能够正常工作的一个核心功能类。

 

下面我们来看一下Context的继承结构:

%title插图%num

Context的继承结构还是稍微有点复杂的,可以看到,直系子类有两个,一个是ContextWrapper,一个是ContextImpl。那么从名字上就可以看出,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类。而ContextWrapper又有三个直接的子类,ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一个带主题的封装类,而它有一个直接子类就是Activity。

 

那么在这里我们至少看到了几个所比较熟悉的面孔,Activity、Service、还有Application。由此,其实我们就已经可以得出结论了,Context一共有三种类型,分别是Application、Activity和Service。这三个类虽然分别各种承担着不同的作用,但它们都属于Context的一种,而它们具体Context的功能则是由ContextImpl类去实现的。

 

那么Context到底可以实现哪些功能呢?这个就实在是太多了,弹出Toast、启动Activity、启动Service、发送广播、操作数据库等等等等都需要用到Context。由于Context的具体能力是由ContextImpl类去实现的,因此在*大多数场景下,Activity、Service和Application这三种类型的Context都是可以通用的。不过有几种场景比较特殊,比如启动Activity,还有弹出Dialog。出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。

 

Context数量

那么一个应用程序中到底有多少个Context呢?其实根据上面的Context类型我们就已经可以得出答案了。Context一共有Application、Activity和Service三种类型,因此一个应用程序中Context数量的计算公式就可以这样写:

  1. Context数量 = Activity数量 + Service数量 + 1

上面的1代表着Application的数量,因为一个应用程序中可以有多个Activity和多个Service,但是只能有一个Application。

 

Application Context的设计

基本上每一个应用程序都会有一个自己的Application,并让它继承自系统的Application类,然后在自己的Application类中去封装一些通用的操作。其实这并不是Google所推荐的一种做法,因为这样我们只是把Application当成了一个通用工具类来使用的,而实际上使用一个简单的单例类也可以实现同样的功能。但是根据我的观察,有太多的项目都是这样使用Application的。当然这种做法也并没有什么副作用,只是说明还是有不少人对于Application理解的还有些欠缺。那么这里我们先来对Application的设计进行分析,讲一些大家所不知道的细节,然后再看一下平时使用Application的问题。

 

首先新建一个MyApplication并让它继承自Application,然后在AndroidManifest.xml文件中对MyApplication进行指定,如下所示:

  1. <application  
  2.     android:name=“.MyApplication”  
  3.     android:allowBackup=“true”  
  4.     android:icon=“@drawable/ic_launcher”  
  5.     android:label=“@string/app_name”  
  6.     android:theme=“@style/AppTheme” >  
  7.     ……
  8. </application>  

指定完成后,当我们的程序启动时Android系统就会创建一个MyApplication的实例,如果这里不指定的话就会默认创建一个Application的实例。

 

前面提到过,现在很多的Application都是被当作通用工具类来使用的,那么既然作为一个通用工具类,我们要怎样才能获取到它的实例呢?如下所示:

  1. public class MainActivity extends Activity {  
  2.     @Override  
  3.     protected void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         setContentView(R.layout.activity_main);
  6.         MyApplication myApp = (MyApplication) getApplication();
  7.         Log.d(“TAG”, “getApplication is ” + myApp);  
  8.     }
  9. }

可以看到,代码很简单,只需要调用getApplication()方法就能拿到我们自定义的Application的实例了,打印结果如下所示:

 

%title插图%num

那么除了getApplication()方法,其实还有一个getApplicationContext()方法,这两个方法看上去好像有点关联,那么它们的区别是什么呢?我们将代码修改一下:

  1. public class MainActivity extends Activity {  
  2.     @Override  
  3.     protected void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         setContentView(R.layout.activity_main);
  6.         MyApplication myApp = (MyApplication) getApplication();
  7.         Log.d(“TAG”, “getApplication is ” + myApp);  
  8.         Context appContext = getApplicationContext();
  9.         Log.d(“TAG”, “getApplicationContext is ” + appContext);  
  10.     }
  11. }

同样,我们把getApplicationContext()的结果打印了出来,现在重新运行代码,结果如下图所示:

 

%title插图%num

 

咦?好像打印出的结果是一样的呀,连后面的内存地址都是相同的,看来它们是同一个对象。其实这个结果也很好理解,因为前面已经说过了,Application本身就是一个Context,所以这里获取getApplicationContext()得到的结果就是MyApplication本身的实例。

 

那么有的朋友可能就会问了,既然这两个方法得到的结果都是相同的,那么Android为什么要提供两个功能重复的方法呢?实际上这两个方法在作用域上有比较大的区别。getApplication()方法的语义性非常强,一看就知道是用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那么也许在*大多数情况下我们都是在Activity或者Service中使用Application的,但是如果在一些其它的场景,比如BroadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法了,如下所示:

  1. public class MyReceiver extends BroadcastReceiver {  
  2.     @Override  
  3.     public void onReceive(Context context, Intent intent) {  
  4.         MyApplication myApp = (MyApplication) context.getApplicationContext();
  5.         Log.d(“TAG”, “myApp is ” + myApp);  
  6.     }
  7. }

也就是说,getApplicationContext()方法的作用域会更广一些,任何一个Context的实例,只要调用getApplicationContext()方法都可以拿到我们的Application对象。

那么更加细心的朋友会发现,除了这两个方法之外,其实还有一个getBaseContext()方法,这个baseContext又是什么东西呢?我们还是通过打印的方式来验证一下:

 

%title插图%num

 

哦?这次得到的是不同的对象了,getBaseContext()方法得到的是一个ContextImpl对象。这个ContextImpl是不是感觉有点似曾相识?回去看一下Context的继承结构图吧,ContextImpl正是上下文功能的实现类。也就是说像Application、Activity这样的类其实并不会去具体实现Context的功能,而仅仅是做了一层接口封装而已,Context的具体功能都是由ContextImpl类去完成的。那么这样的设计到底是怎么实现的呢?我们还是来看一下源码吧。因为Application、Activity、Service都是直接或间接继承自ContextWrapper的,我们就直接看ContextWrapper的源码,如下所示:

  1. /** 
  2.  * Proxying implementation of Context that simply delegates all of its calls to 
  3.  * another Context.  Can be subclassed to modify behavior without changing 
  4.  * the original Context. 
  5.  */  
  6. public class ContextWrapper extends Context {  
  7.     Context mBase;
  8.     /** 
  9.      * Set the base context for this ContextWrapper.  All calls will then be 
  10.      * delegated to the base context.  Throws 
  11.      * IllegalStateException if a base context has already been set. 
  12.      *  
  13.      * @param base The new base context for this wrapper. 
  14.      */  
  15.     protected void attachBaseContext(Context base) {  
  16.         if (mBase != null) {  
  17.             throw new IllegalStateException(“Base context already set”);  
  18.         }
  19.         mBase = base;
  20.     }
  21.     /** 
  22.      * @return the base context as set by the constructor or setBaseContext 
  23.      */  
  24.     public Context getBaseContext() {  
  25.         return mBase;  
  26.     }
  27.     @Override  
  28.     public AssetManager getAssets() {  
  29.         return mBase.getAssets();  
  30.     }
  31.     @Override  
  32.     public Resources getResources() {  
  33.         return mBase.getResources();  
  34.     }
  35.     @Override  
  36.     public ContentResolver getContentResolver() {  
  37.         return mBase.getContentResolver();  
  38.     }
  39.     @Override  
  40.     public Looper getMainLooper() {  
  41.         return mBase.getMainLooper();  
  42.     }
  43.     @Override  
  44.     public Context getApplicationContext() {  
  45.         return mBase.getApplicationContext();  
  46.     }
  47.     @Override  
  48.     public String getPackageName() {  
  49.         return mBase.getPackageName();  
  50.     }
  51.     @Override  
  52.     public void startActivity(Intent intent) {  
  53.         mBase.startActivity(intent);
  54.     }
  55.     @Override  
  56.     public void sendBroadcast(Intent intent) {  
  57.         mBase.sendBroadcast(intent);
  58.     }
  59.     @Override  
  60.     public Intent registerReceiver(  
  61.         BroadcastReceiver receiver, IntentFilter filter) {
  62.         return mBase.registerReceiver(receiver, filter);  
  63.     }
  64.     @Override  
  65.     public void unregisterReceiver(BroadcastReceiver receiver) {  
  66.         mBase.unregisterReceiver(receiver);
  67.     }
  68.     @Override  
  69.     public ComponentName startService(Intent service) {  
  70.         return mBase.startService(service);  
  71.     }
  72.     @Override  
  73.     public boolean stopService(Intent name) {  
  74.         return mBase.stopService(name);  
  75.     }
  76.     @Override  
  77.     public boolean bindService(Intent service, ServiceConnection conn,  
  78.             int flags) {  
  79.         return mBase.bindService(service, conn, flags);  
  80.     }
  81.     @Override  
  82.     public void unbindService(ServiceConnection conn) {  
  83.         mBase.unbindService(conn);
  84.     }
  85.     @Override  
  86.     public Object getSystemService(String name) {  
  87.         return mBase.getSystemService(name);  
  88.     }
  89.     ……
  90. }

由于ContextWrapper中的方法还是非常多的,我就进行了一些筛选,只贴出来了部分方法。那么上面的这些方法相信大家都是非常熟悉的,getResources()、getPackageName()、getSystemService()等等都是我们经常要用到的方法。那么所有这些方法的实现又是什么样的呢?其实所有ContextWrapper中方法的实现都非常统一,就是调用了mBase对象中对应当前方法名的方法。

 

那么这个mBase对象又是什么呢?我们来看第16行的attachBaseContext()方法,这个方法中传入了一个base参数,并把这个参数赋值给了mBase对象。而attachBaseContext()方法其实是由系统来调用的,它会把ContextImpl对象作为参数传递到attachBaseContext()方法当中,从而赋值给mBase对象,之后ContextWrapper中的所有方法其实都是通过这种委托的机制交由ContextImpl去具体实现的,所以说ContextImpl是上下文功能的实现类是非常准确的。

 

那么另外再看一下我们刚刚打印的getBaseContext()方法,在第26行。这个方法只有一行代码,就是返回了mBase对象而已,而mBase对象其实就是ContextImpl对象,因此刚才的打印结果也得到了印证。

 

使用Application的问题

虽说Application的用法确实非常简单,但是我们平时的开发工作当中也着实存在着不少Application误用的场景,那么今天就来看一看有哪些比较容易犯错的地方是我们应该注意的。

 

Application是Context的其中一种类型,那么是否就意味着,只要是Application的实例,就能随时使用Context的各种方法呢?我们来做个实验试一下就知道了:

  1. public class MyApplication extends Application {  
  2.     public MyApplication() {  
  3.         String packageName = getPackageName();
  4.         Log.d(“TAG”, “package name is ” + packageName);  
  5.     }
  6. }

这是一个非常简单的自定义Application,我们在MyApplication的构造方法当中获取了当前应用程序的包名,并打印出来。获取包名使用了getPackageName()方法,这个方法就是由Context提供的。那么上面的代码能正常运行吗?跑一下就知道了,你将会看到如下所示的结果:

 

%title插图%num

 

应用程序一启动就立刻崩溃了,报的是一个空指针异常。看起来好像挺简单的一段代码,怎么就会成空指针了呢?但是如果你尝试把代码改成下面的写法,就会发现一切正常了:

  1. public class MyApplication extends Application {  
  2.     @Override  
  3.     public void onCreate() {  
  4.         super.onCreate();  
  5.         String packageName = getPackageName();
  6.         Log.d(“TAG”, “package name is ” + packageName);  
  7.     }
  8. }

运行结果如下所示:

 

%title插图%num

 

在构造方法中调用Context的方法就会崩溃,在onCreate()方法中调用Context的方法就一切正常,那么这两个方法之间到底发生了什么事情呢?我们重新回顾一下ContextWrapper类的源码,ContextWrapper中有一个attachBaseContext()方法,这个方法会将传入的一个Context参数赋值给mBase对象,之后mBase对象就有值了。而我们又知道,所有Context的方法都是调用这个mBase对象的同名方法,那么也就是说如果在mBase对象还没赋值的情况下就去调用Context中的任何一个方法时,就会出现空指针异常,上面的代码就是这种情况。Application中方法的执行顺序如下图所示:

 

%title插图%num

 

Application中在onCreate()方法里去初始化各种全局的变量数据是一种比较推荐的做法,但是如果你想把初始化的时间点提前到*致,也可以去重写attachBaseContext()方法,如下所示:

  1. public class MyApplication extends Application {  
  2.     @Override  
  3.     protected void attachBaseContext(Context base) {  
  4.         // 在这里调用Context的方法会崩溃  
  5.         super.attachBaseContext(base);  
  6.         // 在这里可以正常调用Context的方法  
  7.     }
  8. }

以上是我们平时在使用Application时需要注意的一个点,下面再来介绍另外一种非常普遍的Application误用情况。

 

其实Android官方并不太推荐我们使用自定义的Application,基本上只有需要做一些全局初始化的时候可能才需要用到自定义Application,官方文档描述如下:

%title插图%num

但是就我的观察而言,现在自定义Application的使用情况基本上可以达到100%了,也就是我们平时自己写测试demo的时候可能不会使用,正式的项目几乎全部都会使用自定义Application。可是使用归使用,有不少项目对自定义Application的用法并不到位,正如官方文档中所表述的一样,多数项目只是把自定义Application当成了一个通用工具类,而这个功能并不需要借助Application来实现,使用单例可能是一种更加标准的方式。

 

不过自定义Application也并没有什么副作用,它和单例模式二选一都可以实现同样的功能,但是我见过有一些项目,会把自定义Application和单例模式混合到一起使用,这就让人大跌眼镜了。一个非常典型的例子如下所示:

  1. public class MyApplication extends Application {  
  2.     private static MyApplication app;  
  3.     public static MyApplication getInstance() {  
  4.         if (app == null) {  
  5.             app = new MyApplication();  
  6.         }
  7.         return app;  
  8.     }
  9. }

就像单例模式一样,这里提供了一个getInstance()方法,用于获取MyApplication的实例,有了这个实例之后,就可以调用MyApplication中的各种工具方法了。

 

但是这种写法对吗?这种写法是大错特错!因为我们知道Application是属于系统组件,系统组件的实例是要由系统来去创建的,如果这里我们自己去new一个MyApplication的实例,它就只是一个普通的Java对象而已,而不具备任何Context的能力。有很多人向我反馈使用 LitePal 时发生了空指针错误其实都是由于这个原因,因为你提供给LitePal的只是一个普通的Java对象,它无法通过这个对象来进行Context操作。

 

那么如果真的想要提供一个获取MyApplication实例的方法,比较标准的写法又是什么样的呢?其实这里我们只需谨记一点,Application全局只有一个,它本身就已经是单例了,无需再用单例模式去为它做多重实例保护了,代码如下所示:

  1. public class MyApplication extends Application {  
  2.     private static MyApplication app;  
  3.     public static MyApplication getInstance() {  
  4.         return app;  
  5.     }
  6.     @Override  
  7.     public void onCreate() {  
  8.         super.onCreate();  
  9.         app = this;  
  10.     }
  11. }

getInstance()方法可以照常提供,但是里面不要做任何逻辑判断,直接返回app对象就可以了,而app对象又是什么呢?在onCreate()方法中我们将app对象赋值成this,this就是当前Application的实例,那么app也就是当前Application的实例了。

 

4、Context的应用场景

%title插图%num

 

 

start activity :    需要提供一个task  除了activity其他的context都没有task,     如果在intent 的flag 添加NEW_TASK  属性创建一个新的task,其他context也是可以start activity的

show dialog  :    dialog需要依附一个窗口 只有activity自带一个窗口,如果设置dialog为system.alert  使dialog依附系统窗口 ,其他context也是可以show dialog的

layout inflate :   在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,因为只有activity 是继承的ContextThemeWrapper带有theme。

其他context可以通过ContextThemeWrapper mContextThemeWrapper = new ContextThemeWrapper(context, theme);

创建一个带theme的context对象ContextThemeWrapper使用,这样其他context也可创建带theme的layout

 

 

大家注意看到有一些NO上添加了一些数字,其实这些从能力上来说是YES,但是为什么说是NO呢?下面一个一个解释:

数字1:启动Activity在这些类中是可以的,但是需要创建一个新的task。一般情况不推荐。

数字2:在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。

数字3:在receiver为null时允许,在4.2或以上的版本中,用于获取黏性广播的当前值。(可以无视)

注:ContentProvider、BroadcastReceiver之所以在上述表格中,是因为在其内部方法中都有一个context用于使用。

 

 

好了,关于Context的介绍就到这里吧,内容还是比较简单易懂的,希望大家通过这篇文章可以理解Context更多的细节,并且不要去犯使用Context时的一些低级错误。

ios之Windows环境下开发ios环境部署

ios之Windows环境下开发ios环境部署
我们都知道开发iPhone等ios平台的移动应用时需要使用Mac本,但是Mac本都比较昂贵,所以我们可以采用Windows7上利用VMWare安装Mac操作系统的方法来模拟ios开发环境,达到降低成本的目的。
1.相关配置
操作系统:windows10
Work station:VMWare10
Mac操作操作系统:OS X 10.8

2.相关资源下载地址
(1)VMWare10的资源比较多,可以到网上自己下载
http://www.xp510.com/xiazai/ossoft/desktools/22610.html
(2)OS X 10.8下载地址
http://download.csdn.net/detail/tianxuexuankui/6838565
(3)VMWare上的Mac补丁
http://download.csdn.net/detail/tianxuexuankui/6838579
(4)dmg格式转换成iso格式的工具UltraISO
http://www.cngr.cn/dir/209/271/2009032738116.html

3.安装过程
a.安装VMWare%title插图%num

b.安装VMWare的Mac补丁
将补丁文件下载之后,解压缩。打开安装文件的windows目录,右键以管理员身份运行install.cmd

c.创建虚拟机
废话不说了
Windows下搭建IOS开发环境(一)
http://blog.csdn.net/lizhenmingdirk/article/details/29850159

Windows下搭建IOS开发环境(二)
http://blog.csdn.net/lizhenmingdirk/article/details/31784441

虚拟机不是全屏显示,需要安装Vmware tools
http://blog.csdn.net/lizhenmingdirk/article/details/32100599

*后实现效果

%title插图%num
注意:
1,VM用10的就够了,我升到12了,也没用,os系统文件没找到
2,dmg格式的镜像文件一定要是OS X 10.8.5的,这样才能安装Xcode5.0.1
3,其他的版本就不用测试了,我花了一天的时间,测试了OS X 10.9 10.10 10.11三个版本都不行。。

Windows下搭建IOS开发环境

1. 安装VMWare12 , 这个网上很多的教程,我就不在这里说了,不会的同学自行百度

2.OS X 10.8下载,http://download.csdn.net/detail/tianxuexuankui/6838565。 这个下载的格式是dmg的

3.VMWare上的Mac补丁 这个必须安装成功,可能会遇到困难,也可能直接成功。

可以在http://download.csdn.net/detail/sinat_32806321/9268655 这里下载

4.dmg格式转换成iso格式的工具UltraISO

http://www.cngr.cn/dir/209/271/2009032738116.html

VMWare上的Mac补丁 安装可能会有闪退或者安装不成功,打开vmWare 里面就没有Mac选项
出现问题的时候,一般会提示vmxsmc.exe已停止响应,再次打开VMware workstation虚拟机软件发现Mac osx虚拟机选项还是没有出现。

修改的步骤如下:

http://jingyan.baidu.com/album/0aa223755b0cde88cd0d646c.html?picindex=1

建立好了空的一个虚拟机后,就要把is文件关联进来,

启动刚刚配置好的虚拟机,有部分虚拟机会出现类似我下面出现这种情况,解决这种情况是找到所配置安装的虚拟机中mac 的目录,在目录下的xxxx.vmx文件,使用记事本打开后,在 smc.present = “TRUE” 后添加“smc.version = 0”(建议您复制,不包括引号)后保存,问题即可解决。重启该虚拟机!

%title插图%num

%title插图%num

%title插图%num

%title插图%num

稍等一段时间之后,进入到语言的选择界面

%title插图%num

这里我选择的是简体中文,然后点击向右的箭头,进入下一步

%title插图%num

选择使用工具里面的磁盘工具,进行分区

%title插图%num

按照上图的方式进行设置后,对分区进行命名

%title插图%num

选择刚刚创建的分区,对数据进行格式化,如下图所示操作。点击右下角抹掉

%title插图%num

关闭分区工具,选择重新安装OS X

%title插图%num

点击继续按钮

%title插图%num

选择同意条款,进入下一项设置

%title插图%num

选择刚刚创建的分区,点击安装选项进行安装

%title插图%num

安装的过程大概需要半小时左右的时间,等待安装完成之后,进行简单的设置,包括开机密码、Apple ID和Icloud、find my Mac等操作。就可以进入到Mac OS X 10.8的操作系统了。界面如下

%title插图%num

安装好Mac操作系统后,打开里面的浏览器就可以直接进入到Apple的官方网站,在网站里面搜索xcode就可以进入到Xcode的下载界面
这里需要注意下,不是所有的Xcode都可以使用的,Xcode和Mac OS X操作系统需要一定的相互匹配关系的,具体的情况可以参考下面

Xcode和Mac os x对应关系

*后安装完成后,mac系统在虚拟机中没有全屏,这个时候需安装一个软件,vmware tools for mac 。可以找下*新版的,这里我给一个百度网盘地址,http://pan.baidu.com/share/link?shareid=3384093857&uk=4195607876&app=zd。
下载VMware tools FOR MAC镜像文件,记住是镜像文件,后缀为.iso格式。如果你找不到新版的,那么可以使用网盘中的,在下面已经给出。

关闭你的虚拟机,选择编辑此虚拟机,然后吧把镜像文件添加到DVD/CD 中去,打开虚拟机的MAC系统,这样就会自动的加载我们的文件了。

6
进入系统后,打开Finder,然后打开Vmware DVD里面的内容,你就可以看到一个安装文件,安装即可,然后重新启动就是全屏了。

WIN10下的IOS开发,基于Swift语言

1.安装虚拟机和macos系统:

https://www.52pojie.cn/thread-804000-1-1.html
※务必在安装完系统后安装VMtools,方便将文件直接拖入虚拟系统中(虚拟机的网络条件不太好)。

虚拟机参数设置见下图:(硬盘*好预留40G,不然可能无法安装Xcode,内存当然越大越好,但要注意勿压榨完主系统的内存)

%title插图%num
2.下载Xcode

*后登陆:
https://developer.apple.com/download/more/

搜索栏搜索Xcode (为兼容macos系统,请下载9.4.1版本)

%title插图%num

Swift语言:
Swift语言的语法学习可参见b站,MIT课程等。
4.完成效果概览:

%title插图%num

WIN10下的ios开发

电脑原生系统:Windows10,基于此,需要以下软件和环境:

Ø VMware Workstation Pro v15.0.0

Ø 解锁工具Unlocker v3.0.0

Ø macOS Mojave 10.14懒人版

Ø Xcode9.4.1

Ø swift 4.1.2

VMware Workstation+macOS配置,参见:
https://www.52pojie.cn/thread-804000-1-1.html
※注意:macOS安装完成后务必在Vmware上方“虚拟机”选择安装Vmware tools
内存配置见下图

%title插图%num

安装Xcode

Ø Xcode版本:9.4.1 (为了兼容macO,选择稍老版本的Xcode)

Ø 编程语言版本:swift 4.1.2 (Apple.Inc 自主研发的面向Apple开发的语言)

*,在win系统下去苹果官网[1]下载Xcode 9.4.1(旧版本,不然不兼容虚拟机上的mac版本)
https://developer.apple.com/download/more/
搜索栏搜索Xcode

※ 可将文件下载到WIN系统中,然后利用VMtools的功能直接将文件拖入虚拟机的macOS桌面上,完成安装。

%title插图%num
如此,即可在WIN10的环境下开发ios程序。

xcode入门_Xcode12入门

xcode入门

Xcode is at the center of all development on Apple’s platforms, and with Xcode 12, it has a fresh new look to match macOS Big Sur. Xcode 12 for macOS Universal Apps beta is a distribution of Xcode 12 beta for creating Universal Mac apps that run on both Apple silicon and Intel-based Mac computers.

Xcode是Apple平台上所有开发的核心,并且通过Xcode 12,它具有与macOS Big Sur匹配的崭新外观。 适用于macOS的Xcode 12 Universal Apps beta是Xcode 12 beta的发行版,用于创建可在Apple芯片和基于Intel的Mac计算机上运行的Universal Mac应用程序。

Here is some introduction about new updates in xcode, it is Xcode 12 Beta release. Update your apps to use new features and test your apps against changes in API. New document tabs make opening multiple files fast and lightweight to support interface files, and logs and project files each open in their own tab. Navigator fonts now match the system size, or can be set to small, medium, or large. And Xcode 12 builds macOS Universal apps by default to support new Macs with Apple silicon.

这是有关xcode中新更新的一些介绍,它是Xcode 12 Beta版本。 更新您的应用程序以使用新功能,并针对API的更改测试您的应用程序。 新的文档选项卡使打开多个文件既快速又轻便,以支持界面文件,并且日志和项目文件均在各自的选项卡中打开。 导航器字体现在与系统大小匹配,或者可以设置为小号,中号或大号。 Xcode 12默认情况下会构建macOS Universal应用程序,以支持带有Apple芯片的新Mac。

Image for post
developer.apple.com developer.apple.com

Xcode 12 for macOS Universal Apps beta includes SDKs for iOS 14, iPadOS 14, and macOS 11. The Xcode 12 for macOS Universal Apps beta release supports on-device debugging for iOS 9 and later. Xcode 12 for macOS Universal Apps beta requires a Mac running macOS 10.15.4 or later.

适用于macOS Universal Apps beta的Xcode 12包括适用于iOS 14,iPadOS 14和macOS 11的SDK。适用于macOS Universal Apps beta的Xcode 12支持针对iOS 9及更高版本的设备上调试。 Mac OS X的Xcode 12 Universal Apps beta需要运行macOS 10.15.4或更高版本的Mac。

Xcode’s run destination menu now shows an “Any Mac” destination for Mac schemes. This is a new build destination that builds each target in the scheme for all of their supported architectures, regardless of the native architecture of the local Mac.

Xcode的运行目标菜单现在显示Mac方案的“ Any Mac”目标。 这是一个新的构建目标,可以为方案中的所有受支持体系结构构建每个目标,而与本地Mac的本机体系结构无关。

New Features

新功能

Documents can now be opened in their own tab, making it easy to quickly switch between files while maintaining the rest of Xcode’s configuration. Option-click or double-click to open a document in a tab.

现在可以在它们自己的选项卡中打开文档,从而可以轻松地在文件之间快速切换,同时保持Xcode的其余配置。 按住Option键单击或双击以在选项卡中打开文档。

Xcode adds support for previewing widgets, App Clips, and content in Swift packages. For more seamless live previewing on device, Xcode installs the new Xcode Previews app for iOS 14 and iPadOS 14.

Xcode增加了对预览小部件,应用程序剪辑和Swift包中的内容的支持。 为了在设备上进行更无缝的实时预览,Xcode安装了适用于iOS 14和iPadOS 14的新Xcode Previews应用。

The new LibraryContentProvider protocol gives you the ability to show your views and modifiers in Xcode’s library.

新的LibraryContentProvider协议使您能够在Xcode的库中显示视图和修饰符。

Code completions have a new, focused, user interface, making it easier to find a completion. Completions are also more accurate and up to 12 times faster in Xcode 12.

代码补全具有一个新的,集中的用户界面,使查找补全更加容易。 Xcode 12中的完成也更准确,速度*高可提高12倍。

资产目录 (Asset Catalogs)

It adds support for Scalable Vector Graphic (SVG) image assets. These preserve their vector representation with deployment targets of macOS 10.15 or later, iOS 13 or later, and iPadOS 13 or later.

它增加了对可缩放矢量图形(SVG)图像资产的支持。 它们使用macOS 10.15或更高版本,iOS 13或更高版本以及iPadOS 13或更高版本的部署目标保留其矢量表示。

The required pixel size is now shown for complication placeholder images.

现在显示了复杂占位符图像所需的像素大小。

The “New Asset” menu has been changed to organize asset types by platform.

“新资产”菜单已更改为按平台组织资产类型。

调试 (Debugging)

When a process crashes under the debugger, Xcode prints the crash messages in the Console. These messages are similar to the ones displayed in CrashReporter.

当进程在调试器下崩溃时,Xcode在控制台中打印崩溃消息。 这些消息类似于CrashReporter中显示的消息。

Xcode debugger annotations will highlight source code with greater opacity to improve visibility in several Xcode themes.

Xcode调试器批注将以更高的不透明度突出显示源代码,以提高在多个Xcode主题中的可见性。

If you have disabled breakpoints in the Breakpoint Navigator, you can use the contextual menu to delete all the disabled breakpoints.

如果已在“断点导航器”中禁用了断点,则可以使用上下文菜单删除所有禁用的断点。

When paused in the debugger, stepping out of a block will unwind and land in a frame with debug symbol.

在调试器中暂停时,跳出块会展开并降落在带有调试符号的帧中。

设备 (Devices)

The “Add Device” sheet in the Devices and Simulators window is now resizable.

现在,“设备和模拟器”窗口中的“添加设备”工作表可调整大小。

The Devices and Simulators window permits selecting multiple devices in the navigator, so they can be unpaired together.

“设备和模拟器”窗口允许在导航器中选择多个设备,因此可以将它们取消配对。

界面生成器 (Interface Builder)

It Added support for the new safeAreaLayoutGuide on NSView introduced in macOS 11.

它增加了对macOS 11中引入的NSView上新的safeAreaLayoutGuide的支持。

Introduced a new minimap for the Interface Builder canvas. You can show and hide the minimap with Editor > Canvas > Minimap. Drag the minimap to any corner of the canvas.

为Interface Builder画布引入了一个新的小地图。 您可以使用“编辑器”>“画布”>“小地图”显示和隐藏小地图。 将小地图拖到画布的任何角落。

Find and Replace now includes matches in attributed string literals.

查找和替换现在在属性字符串文字中包含匹配项。

Interface Builder now has a Current Date option for NSDatePicker.

Interface Builder现在为NSDatePicker提供了“当前日期”选项。

Standard spacing constraints are now created by default when items are positioned a standard distance from each other.

现在,默认情况下,当项目彼此之间的距离为标准距离时,会创建标准间距约束。

Added support for SF Symbols in macOS 11.

在macOS 11中添加了对SF符号的支持。

Added support for UIButton.ButtonType.close .

添加了对UIButton.ButtonType.close的支持。

Added support for the new toolbarStyle in macOS 11.

在macOS 11中添加了对新工具toolbarStyle支持。

Added support for the new subtitle property in macOS 11.

在macOS 11中添加了对新subtitle属性的支持。

Added support for the new NSSearchToolbarItem in macOS 11.

在macOS 11中添加了对新NSSearchToolbarItem支持。

Added support for selecting text styles in macOS 11.

添加了对在macOS 11中选择文本样式的支持。

Added support for the new NSTableViewStyle with Automatic, Full Width, Inset, and Source List options.

添加了对带有自动,全宽,插入和源列表选项的新NSTableViewStyle支持。

游乐场 (Playgrounds)

In Xcode Playgrounds now you can import and use Swift packages and frameworks. Select the Build Active Scheme checkbox in the playground’s File inspector and ensure that the active scheme builds the package or framework target.

现在,您可以在Xcode Playgrounds中导入和使用Swift包和框架。 选中游乐场的文件检查器中的“构建活动方案”复选框,并确保活动方案可构建包或框架目标。

Xcode’s Report Navigator now includes Playground build logs.

Xcode的Report Navigator现在包括Playground构建日志。

Xcode Playgrounds now build the active scheme’s targets and make them importable when Build Active Scheme is enabled in the File inspector.

Xcode Playgrounds现在可以构建活动方案的目标,并在文件检查器中启用“构建活动方案”后将其导入。

预告片 (Previews)

Xcode now considers edited files and open previews when selecting which app renders previews

Xcode现在可以在选择哪个应用程序呈现预览时考虑编辑过的文件并打开预览

Each preview now has buttons to start Live Preview, Preview on Device, Inspect Preview, and Duplicate Preview.

现在,每个预览都有用于启动实时预览,在设备上预览,检查预览和重复预览的按钮。

You can click the Inspect Preview button to see modifier recommendations for the selected view and search for the modifier you want to apply.

您可以单击“检查预览”按钮以查看选定视图的修改器建议,并搜索要应用的修改器。

Xcode supports previewing widgets. For an example of how to configure a widget preview, see WidgetPreviewContext.

Xcode支持预览小部件。 有关如何配置窗口小部件预览的示例,请参见WidgetPreviewContext 。

The Attributes inspector now offers quick actions for editing the name, device, layout, preferred color scheme, and accessibility text size of a selected preview.

现在,“属性”检查器提供了快速操作,可用于编辑所选预览的名称,设备,布局,首选配色方案和可访问性文本大小。

Xcode Previews now supports previewing views in frameworks on-device if the framework is linked by an app in the selected scheme.

如果框架通过选定方案中的应用程序链接,则Xcode Previews现在支持在设备上预览框架中的视图。

Xcode now supports previews for App Clips.

Xcode现在支持应用剪辑的预览。

Xcode now connects with the new Xcode Previews app for iOS 14 and iPadOS 14 for greatly improved on-device previews. The Xcode Previews app seamlessly displays changes from Xcode Previews on devices.

Xcode现在可以与适用于iOS 14和iPadOS 14的新Xcode预览应用程序连接,以大大改善设备上的预览。 Xcode Previews应用程序无缝显示设备上Xcode Previews中的更改。

The bottom bar of the canvas now contains a button for quickly inspecting the selected view.

现在,画布的底部栏包含一个用于快速检查所选视图的按钮。

仿真器 (Simulator)

Simulator can display a simulated device in full-screen mode, or tile its window alongside Xcode.

Simulator可以全屏模式显示模拟的设备,也可以将其窗口平铺在Xcode旁边。

Simulator now supports 64-bit and 32-bit processes for watchOS 7. To verify watchOS projects are 64-bit clean in Simulator, make sure ARCHS is set to its default value.

Simulator现在支持watchOS 7的64位和32位进程。要验证watchOS项目在Simulator中是否为64位纯净,请确保将ARCHS设置为其默认值。

Window > Stay on Top keeps device windows in front of other application windows.

窗口>停留在顶部可使设备窗口位于其他应用程序窗口的前面。

Simulator defaults to the internal microphone unless you explicitly choose a different audio source. This avoids triggering phone call mode on Bluetooth headsets which degrades audio quality while listening to music.

模拟器默认为内置麦克风,除非您明确选择其他音频源。 这样可以避免在蓝牙耳机上触发电话呼叫模式,而这会在听音乐时降低音频质量。

Simulator supports simulating Nearby Interaction for devices that support the feature. Dragging the device window around on the screen will update the simulated distance between the two devices. The farther apart the windows are on screen the greater the reported distance.

模拟器支持为支持该功能的设备模拟“邻近交互”。 在屏幕上四处拖动设备窗口将更新两个设备之间的模拟距离。 窗口在屏幕上的距离越远,报告的距离就越大。

Swift (Swift)

Swift indentation has been overhauled, greatly improving the indentation of chained methods calls, especially those that involve nested or trailing closures.

快速缩进已得到全面改进,大大改善了链式方法调用的缩进,特别是那些涉及嵌套或尾随闭包的调用。

A property with an attached property wrapper can now rely on type inference to infer the wrapped value type when using default initialization without empty parentheses on the wrapper attribute. For example:

使用默认初始化时,具有附加属性包装器的属性现在可以依靠类型推断来推断包装的值类型,而在包装器属性上没有空括号。 例如:

Image for post
developer.apple.com developer.apple.com

The wrapped property UseWrapper.value uses default initialization of IntWrapper, and relies on type inference to deduce the type-wrapped value type to be Int.

包装的属性UseWrapper.value使用IntWrapper的默认初始化,并依靠类型推断将类型包装的值类型推论为Int。

Swift now allows the implicit use of self in @escaping closures when reference cycles are unlikely to occur.

现在,当不太可能发生引用循环时,Swift允许在@escaping闭包中隐式使用self。

First, implicit use of self in @escaping closures is now allowed if the user has explicitly captured self in the closure’s capture list, so the following code is now valid:

首先,如果用户已经在闭包的捕获列表中显式捕获了self,则现在允许在@escaping闭包中隐式使用self,因此以下代码现在有效:

Image for post
developer.apple.com developer.apple.com

Second, implicit self is available in @escaping closures when self is a value type, making the following code valid:

其次,当self是值类型时,隐式self在@escaping闭包中可用,使以下代码有效:

Image for post
developer.apple.com developer.apple.com

Notes: Here I try to give description about updates in xcode. It have amazing new features thats helps developers to design apps in easy way. Also It improves the speed for development.

注意:在这里,我尝试提供有关xcode更新的描述。 它具有令人惊叹的新功能,可帮助开发人员轻松设计应用程序。 还可以提高开发速度。

Let me know your thoughts in comment box below!!!

每天 200G 下载流量,求推荐便宜好用的服务器

要求: win 平台主机,*好是国内(因为要向国内的邮箱商发邮件,国外连接速度太渣)
每天要出去 200-300G 的数据(集中于下午 1 点-0 点),所以带宽要求较高。
查了阿里云, 50M 的带宽一个月要 4000 元。而我们只是非常小的学生团队,这样的钱实在出不起。。。

太渣 带宽 Win 好用31 条回复 • 2016-06-30 17:31:46 +08:00
lazycat 1
lazycat 2016-01-20 21:51:23 +08:00 via Android
国内带宽都很贵的亲。。。
longquanwo 2
longquanwo 2016-01-20 21:55:21 +08:00
Azure 官网首页: 1000 元转正活动。首次付款人民币 1000 元, Azure 信用额度有效期为 12 个月,每月赠送 1TB 的流量;
abelyao 3
abelyao 2016-01-20 22:02:55 +08:00 via iPhone
说说项目性质,如果可盈利,或者是公益的,或许有人投资赞助噢
function007 4
function007 2016-01-20 22:05:07 +08:00
每月 6T 出站流量,国内别想便宜了
用日本的吧
wuhanpizi 5
wuhanpizi 2016-01-20 23:28:30 +08:00
自己上服务器吧 百独
alect 6
alect 2016-01-21 01:47:22 +08:00
不知你每天 200 多 G 的下载量是什么内容呢?
ryd994 7
ryd994 2016-01-21 01:50:02 +08:00
你可以和邮件服务器分开,还是说你 200 多 G 全是邮件?!
em70 8
em70 2016-01-21 02:03:11 +08:00
1.能不能压缩数据再发送
2.是不是发垃圾邮件
Marfal 9
Marfal 2016-01-21 02:23:05 +08:00
Linode 8GB 内存套餐,流量是 8T ,带宽是 1000M ,应该够了吧,每月 80 刀,发邮件建议用专业邮件投递服务,自己搭建的话到达率相对低一点。
Starduster 10
Starduster 2016-01-21 03:31:36 +08:00
如果是纯粹的邮件每天 200G ,怎么不被当成垃圾是个更难处理的问题
如果不是这样,建议把需求分开,阿里云这个带宽算正常价格,国内带宽就这么贵。要带宽大还要便宜除非有什么特殊关系在机房,或者靠入侵大水管机器的黑产了。。。
irainsoft 11
irainsoft 2016-01-21 04:52:39 +08:00
每天 200G 下载流量…这是在干啥呢…
irainsoft 12
irainsoft 2016-01-21 04:55:13 +08:00
不要在国内找了 带宽真的很贵邮件可以用专门的邮件服务器啊 日本服务器上想想吧要求还是很高的
jasontse 13
jasontse 2016-01-21 08:22:35 +08:00 via Android
4000 出不起的话真的不用在国内找了
qiayue 14
qiayue 2016-01-21 09:04:09 +08:00 via Android
七牛价格是 0.29 每 G , 200G 是 60 左右,一个月 1800
IDC007 15
IDC007 2016-01-21 09:16:48 +08:00
美国的带宽便宜 哈哈
sharkli 16
sharkli 2016-01-21 09:22:06 +08:00
自己装个百兆宽带进行下载,不行就两条,数据处理完再放外网服务器。
xmoiduts 17
xmoiduts 2016-01-21 10:09:46 +08:00 via Android
10 台阿里云*低配 1 核 1g /每台 5m 带宽?
romotc 18
romotc 2016-01-21 10:23:22 +08:00
200G 数据都是邮件内容?那得多少封邮件…
如果是附件大的话请尝试拆分邮件内容,把附件改成下载链接,这样附件就可以放在国外了。
之前用七牛 3 天 1000 块吓哭了,赶紧弄了个米国服务器,配合着 hostus 的香港做中转速度还行。
UPYUN 19
UPYUN 2016-01-21 10:55:41 +08:00
UPYUN 的流量计费是 0.29 元 /G ,而且如果你一天 200 G 流量的话,我们还按照 1 : 1 的比例赠送 200 G 的存储空间。成本上的话,应该算是同业*低了,你们可以考虑下~
hyq 20
hyq 2016-01-21 11:03:53 +08:00
如果有可能可以找学校网络中心商议下,如果是对学生的福利项目应该会给支持的
Orzpls 21
Orzpls 2016-01-21 11:32:38 +08:00 via Android
你不会在干坏事吧,一个月到 9TB 流量,放在哪儿都不便宜。
zaishanfeng 22
zaishanfeng 2016-01-21 11:56:50 +08:00 via Android
瓷器国就不要想了 比非洲都贵
ranzige 23
ranzige 2016-01-22 08:48:06 +08:00
@UPYUN 看了一下, UP 只有存储,而我们需要的是主机。
thinkxen 24
thinkxen 2016-01-26 20:38:02 +08:00
国内电信 50M 独享的机器 1000 可以多的,也不算很贵呀
当然 BGP 的话就不能比了,差不多就要 4000 了~~~
prondtoo 25
prondtoo 2016-01-29 16:11:42 +08:00
找带宽便宜的城市的机房,上自己的服务器。
abel163 26
abel163 2016-03-04 16:32:12 +08:00
贵州的带宽便宜,可以找我咨询
snsd 27
snsd 2016-03-07 15:55:28 +08:00
@abel163 能拿来挂下载吗?
abel163 28
abel163 2016-03-08 10:25:23 +08:00
@snsd 必须可以啊, 100m 带宽,加我 qq41431935 ,开测试搞下,相比你那 4000 先打个对折
abel163 29
abel163 2016-03-08 10:32:29 +08:00
@snsd 看你是单线,还是双线,如果是要双线建议租 2 台划算,每台 100m ,这样划算
fancyhan 30
fancyhan 2016-06-29 14:06:35 +08:00 ❤️ 1
@abel163 100M *便宜的多少钱?
abel163 31
abel163 2016-06-30 17:31:46 +08:00
@fancyhan 加我 qq 吧

服务器怎么转发请求到另一个外网服务器(不在同一个局域网内)

各位好,有个问题请教下

我们有一个服务是搭在国内的一个机房,但是我们打算把其中一些访问请求,转发到国外的服务器上去

一开始打算用 nginx ,识别某些 URL 请求,然后转发到国外服务器的 IP:80 端口

但是这样总是提示 404

nginx 是不是不能这样用? 还有没有其他的办法

我们之所以这样做是因为有一些请求需要调用国外 API ,国内的服务器经常连接不上,所以就在香港又买了一个服务器,打算把需要调用国外 API 的请求,自动转发到香港服务器上去

服务器 请求 Nginx API8 条回复 • 2016-03-18 09:53:18 +08:00
UnisandK 1
UnisandK 2016-03-17 17:33:14 +08:00
搜 Nginx 反向代理的配置吧
socat 或者 iptables 直接转发端口也行
kendetrics 2
kendetrics 2016-03-17 17:34:54 +08:00
只需要进行转发的是可以试试 vxtrans ,应该比你买服务器划算些
pengpotter 3
pengpotter 2016-03-17 19:11:32 +08:00
@kendetrics vxtrans 需要在目标主机上配置授权。。。但是目标服务器是第三方的。。我没法在上面操作授权
kendetrics 4
kendetrics 2016-03-17 19:13:19 +08:00
@pengpotter 第三方的那的确没办法了
cyberdak 5
cyberdak 2016-03-17 19:22:07 +08:00
这么配置是正常的呀
你需要找到为什么 nginx 转发的时候 404

如果用反代的话,香港服务器挂掉,这边会提示服务器连接不上。但是也不应该出现 404 的

楼主可以贴一下 nginx 的配置文件吗
pengpotter 6
pengpotter 2016-03-17 20:51:38 +08:00
@cyberdak 谢谢,我检查了下,这样用法是正确的,的确是配置上的问题
cyberdak 7
cyberdak 2016-03-17 21:03:14 +08:00
@pengpotter 现在解决了吗?
pengpotter 8
pengpotter 2016-03-18 09:53:18 +08:00
@cyberdak 解决了,直接用 nginx 就可以转发了

debian 与 centos, apache 与 nginx。问题不重要,重要的是解决的过程

抱歉,ssh的字符有空格,复制进来排版会乱掉,编辑了几次也不行,先凑合看吧,我再改改。 受人所托,要做一个比较正式的网站,可自己以前折腾都是 debian + lighttpd + php-fastcgi + sqlite 这样的奇葩组合,肯定不能这么用。

首先是系统,一直都是 debian 而且也没有什么不稳定的情况,但 centos 在很多人口中似乎都是:红帽亲儿子,企业,稳定。于是便纠结应该用自己熟悉的 debian 还是换到口碑似乎更好的 centos 。

第二是 web 服务器,自己用 lighttpd 只是为了低资源占用,普遍用的应该都是 apache 和 nginx 吧,但用法也有好多种。 单 apache ,并发弱 但 mod-php 性能好,资源占用高。 单 nginx ,并发强 但 php-fpm 会有 502 ,资源占用低。 nginx 反代 apache ,前端 nginx 抗并发,后端 apache 处理 php ,似乎是*佳方案。

开始动手测试,测试是在虚拟机下进行的,两台虚拟机都是 512M 内存,系统是 debian 8 和 centos 7 ,都用默认源,都用 apt/yum 安装。

——————————apache 部分—————————— Centos———————————————————— Server version: Apache/2.4.6 (CentOS) Server built: Nov 19 2015 21:43:13 Debian———————————————————— Server version: Apache/2.4.10 (Debian) Server built: Nov 28 2015 14:05:48 从版本号上看,是 debian 中的 apache 较新,但是有听到一种说法, centos 中的包都有 backport ,虽然版本号旧,但软件不旧,具体不知如何考证。

——————————php 部分—————————— Centos———————————————————— PHP 5.4.16 (cli) (built: Jun 23 2015 21:17:27) Copyright (c) 1997-2013 The PHP Group Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies Debian———————————————————— PHP 5.6.17-0+deb8u1 (cli) (built: Jan 13 2016 09:10:12) Copyright (c) 1997-2015 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies 从版本号上看,是 debian 中的 php 较新。 但是安装 php-gd 的时候, centos 中是 bundle 版, debian 中是 dev 版, dev 字面上应该是开发版。明明用的是 debian 的 stable 源,为什么会是开发版?

——————————mysql 部分—————————— Centos———————————————————— mysql Ver 15.1 Distrib 5.5.44-MariaDB, for Linux (x86_64) using readline 5.1 Debian———————————————————— mysql Ver 14.14 Distrib 5.5.47, for debian-linux-gnu (x86_64) using readline 6.3 数据库这里就不能看版本号了,因为 centos 用 yum 安装 mysql 会自动安装 mariadb 。

debian 和 centos 下分别安装 Discuz x3.2 后进行压力测试,放个雅黑探针用于观测系统负载。 ——————————压力测试—————————— 使用 apache 的压力测试工具, ab -c 100 -n 100 http://127.0.0.1/forum.php ,之后逐步增加。 Centos———————————————————— Server Software: Apache/2.4.6 Server Hostname: 127.0.0.1 Server Port: 80

Document Path: /forum.php Document Length: 12872 bytes

Concurrency Level: 100 Time taken for tests: 3.589 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 1359500 bytes HTML transferred: 1287200 bytes Requests per second: 27.86 [#/sec] (mean) Time per request: 3589.014 [ms] (mean) Time per request: 35.890 [ms] (mean, across all concurrent requests) Transfer rate: 369.92 [Kbytes/sec] received

Connection Times (ms) min mean[+/-sd] median max Connect: 1 1 0.3 1 2 Processing: 74 1974 996.3 1995 3513 Waiting: 71 1974 996.3 1995 3513 Total: 74 1975 996.0 1997 3514

Percentage of the requests served within a certain time (ms) 50% 1997 66% 2560 75% 2925 80% 3046 90% 3374 95% 3484 98% 3494 99% 3514 100% 3514 (longest request)

Debian———————————————————— Server Software: Apache/2.4.10 Server Hostname: 127.0.0.1 Server Port: 80

Document Path: /forum.php Document Length: 12872 bytes

Concurrency Level: 100 Time taken for tests: 1.215 seconds Complete requests: 100 Failed requests: 0 Total transferred: 1367400 bytes HTML transferred: 1287200 bytes Requests per second: 82.30 [#/sec] (mean) Time per request: 1215.040 [ms] (mean) Time per request: 12.150 [ms] (mean, across all concurrent requests) Transfer rate: 1099.02 [Kbytes/sec] received

Connection Times (ms) min mean[+/-sd] median max Connect: 3 25 4.0 26 27 Processing: 149 705 315.9 706 1187 Waiting: 134 694 316.7 705 1186 Total: 170 730 317.1 732 1212

Percentage of the requests served within a certain time (ms) 50% 732 66% 917 75% 1010 80% 1055 90% 1161 95% 1205 98% 1211 99% 1212 100% 1212 (longest request)

分别测试三次,取*好结果。 测试结果是 debian 的更好,但内存已经满了。 centos 则已经开始使用 swap 了。 系统负载方面也是 debian 更低,但微乎其微,至少和内存方面的差距比起来是这样。 测试结束后内存占用率回落也是 debian 更快, centos 回落速度慢是不是受 swap 硬盘速度的影响不得而知。 centos 是 mariadb 而 debian 是 mysql ,不知道这是不是也是个影响因素。

接下来测试 nginx+apache 和 单 nginx ,在 debian 虚拟机下快照还原后重新安装 nginx+apache———————————————————— 结果忘了保存,压力测试结果比单 apache 更好,资源占用比单 apache 更低。

单 nginx———————————————————— Server Software: nginx/1.6.2 Server Hostname: 127.0.0.1 Server Port: 80

Document Path: /forum.php Document Length: 12871 bytes

Concurrency Level: 100 Time taken for tests: 1.024 seconds Complete requests: 100 Failed requests: 0 Total transferred: 1363960 bytes HTML transferred: 1287100 bytes Requests per second: 97.66 [#/sec] (mean) Time per request: 1023.960 [ms] (mean) Time per request: 10.240 [ms] (mean, across all concurrent requests) Transfer rate: 1300.82 [Kbytes/sec] received

Connection Times (ms) min mean[+/-sd] median max Connect: 9 28 3.4 28 32 Processing: 56 519 288.0 503 991 Waiting: 45 514 287.2 501 991 Total: 73 547 290.2 531 1023

Percentage of the requests served within a certain time (ms) 50% 531 66% 720 75% 819 80% 866 90% 964 95% 1011 98% 1016 99% 1023 100% 1023 (longest request) 测试结果*好,压力测试*好,资源占用*低 而且在压力测试参数增加后, nginx 的测试结果更好了,有点不解。

现在决定用 debian + nginx + php-fpm + mysql 这个组合了,但也留下几个疑问: 为什么那么多人说 centos 要比 debian 稳定? centos 中的软件真的会依靠 backport 做到版本号老,但软件不旧吗? 为什么那么多人推荐 nginx 反代 apache 这种组合?因为后端运算集中的应用下 apache 更为强大?因为 nginx 使用 php-fpm 会出现 502 ? 为什么 debian 的 stable 源中的 php-gd 会是 dev 版?因为这个 dev 版已经经过测试足够稳定了? mariadb 能否取代 mysql ?把 mysql 换成 mariadb 是否更好?我对 mariadb 完全陌生,看来得多学习学习了:) 为什么压力测试时,单 nginx 压力越高,反而表现越好了? 有没有比 debian + nginx + php-fpm + mysql 这个组合更好的方案?似乎问题又回到了原点。。。

第 1 条附言 · 2016-03-25 22:27:04 +08:00
重新编辑发一遍
受人所托,要做一个比较正式的网站,可自己以前折腾都是 debian + lighttpd + php-fastcgi + sqlite 这样的奇葩组合,肯定不能这么用。

首先是系统,一直都是 debian 而且也没有什么不稳定的情况,但 centos 在很多人口中似乎都是:红帽亲儿子,企业,稳定。于是便纠结应该用自己熟悉的 debian 还是换到口碑似乎更好的 centos 。

第二是 web 服务器,自己用 lighttpd 只是为了低资源占用,普遍用的应该都是 apache 和 nginx 吧,但用法也有好多种。
单 apache ,并发弱 但 mod-php 性能好,资源占用高。
单 nginx ,并发强 但 php-fpm 会有 502 ,资源占用低。
nginx 反代 apache ,前端 nginx 抗并发,后端 apache 处理 php ,似乎是*佳方案。

开始动手测试,测试是在虚拟机下进行的,两台虚拟机都是 512M 内存,系统是 debian 8 和 centos 7 ,都用默认源,都用 apt/yum 安装。

apache 部分
Centos
Server version: Apache/2.4.6 (CentOS) Server built: Nov 19 2015 21:43:13

Debian
Server version: Apache/2.4.10 (Debian) Server built: Nov 28 2015 14:05:48

从版本号上看,是 debian 中的 apache 较新,但是有听到一种说法, centos 中的包都有 backport ,虽然版本号旧,但软件不旧,具体不知如何考证。

php 部分
Centos
PHP 5.4.16 (cli) (built: Jun 23 2015 21:17:27)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies

Debian
PHP 5.6.17-0+deb8u1 (cli) (built: Jan 13 2016 09:10:12)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies
with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies

从版本号上看,是 debian 中的 php 较新。
但是安装 php-gd 的时候, centos 中是 bundle 版, debian 中是 dev 版, dev 字面上应该是开发版。明明用的是 debian 的 stable 源,为什么会是开发版?

mysql 部分
Centos
mysql Ver 15.1 Distrib 5.5.44-MariaDB, for Linux (x86_64) using readline 5.1

Debian
mysql Ver 14.14 Distrib 5.5.47, for debian-linux-gnu (x86_64) using readline 6.3

数据库这里就不能看版本号了,因为 centos 用 yum 安装 mysql 会自动安装 mariadb 。

debian 和 centos 下分别安装 Discuz x3.2 后进行压力测试,放个雅黑探针用于观测系统负载。

压力测试部分
使用 apache 的压力测试工具, ab -c 100 -n 100 http://127.0.0.1/forum.php ,之后逐步增加。

Centos
Server Software: Apache/2.4.6
Server Hostname: 127.0.0.1
Server Port: 80

Document Path: /forum.php
Document Length: 12872 bytes

Concurrency Level: 100

第 2 条附言 · 2016-03-25 22:28:31 +08:00
Time taken for tests: 3.589 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Total transferred: 1359500 bytes
HTML transferred: 1287200 bytes
Requests per second: 27.86 [#/sec] (mean)
Time per request: 3589.014 [ms] (mean)
Time per request: 35.890 [ms] (mean, across all concurrent requests)
Transfer rate: 369.92 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 1 1 0.3 1 2
Processing: 74 1974 996.3 1995 3513
Waiting: 71 1974 996.3 1995 3513
Total: 74 1975 996.0 1997 3514

Percentage of the requests served within a certain time (ms)
50% 1997
66% 2560
75% 2925
80% 3046
90% 3374
95% 3484
98% 3494
99% 3514
100% 3514 (longest request)

## Debian
Server Software: Apache/2.4.10
Server Hostname: 127.0.0.1
Server Port: 80

Document Path: /forum.php
Document Length: 12872 bytes

Concurrency Level: 100
Time taken for tests: 1.215 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 1367400 bytes
HTML transferred: 1287200 bytes
Requests per second: 82.30 [#/sec] (mean)
Time per request: 1215.040 [ms] (mean)
Time per request: 12.150 [ms] (mean, across all concurrent requests)
Transfer rate: 1099.02 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 3 25 4.0 26 27
Processing: 149 705 315.9 706 1187
Waiting: 134 694 316.7 705 1186
Total: 170 730 317.1 732 1212

Percentage of the requests served within a certain time (ms)
50% 732
66% 917
75% 1010
80% 1055
90% 1161
95% 1205
98% 1211
99% 1212
100% 1212 (longest request)
第 3 条附言 · 2016-03-25 22:29:09 +08:00
分别测试三次,取*好结果。
测试结果是 debian 的更好,但内存已经满了。 centos 则已经开始使用 swap 了。
系统负载方面也是 debian 更低,但微乎其微,至少和内存方面的差距比起来是这样。
测试结束后内存占用率回落也是 debian 更快, centos 回落速度慢是不是受 swap 硬盘速度的影响不得而知。 centos 是 mariadb 而 debian 是 mysql ,不知道这是不是也是个影响因素。

# 接下来测试 nginx+apache 和 单 nginx ,在 debian 虚拟机下快照还原后重新安装
## nginx+apache
结果忘了保存,压力测试结果比单 apache 更好,资源占用比单 apache 更低。

## 单 nginx
Server Software: nginx/1.6.2
Server Hostname: 127.0.0.1
Server Port: 80

Document Path: /forum.php
Document Length: 12871 bytes

Concurrency Level: 100
Time taken for tests: 1.024 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 1363960 bytes
HTML transferred: 1287100 bytes
Requests per second: 97.66 [#/sec] (mean)
Time per request: 1023.960 [ms] (mean)
Time per request: 10.240 [ms] (mean, across all concurrent requests)
Transfer rate: 1300.82 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 9 28 3.4 28 32
Processing: 56 519 288.0 503 991
Waiting: 45 514 287.2 501 991
Total: 73 547 290.2 531 1023

Percentage of the requests served within a certain time (ms)
50% 531
66% 720
75% 819
80% 866
90% 964
95% 1011
98% 1016
99% 1023
100% 1023 (longest request)
测试结果*好,压力测试*好,资源占用*低
而且在压力测试参数增加后, nginx 的测试结果更好了,有点不解。

# 结果
现在决定用 debian + nginx + php-fpm + mysql 这个组合了,但也留下几个疑问:
为什么那么多人说 centos 要比 debian 稳定? centos 中的软件真的会依靠 backport 做到版本号老,但软件不旧吗?
为什么那么多人推荐 nginx 反代 apache 这种组合?因为后端运算集中的应用下 apache 更为强大?因为 nginx 使用 php-fpm 会出现 502 ?
为什么 debian 的 stable 源中的 php-gd 会是 dev 版?因为这个 dev 版已经经过测试足够稳定了?
mariadb 能否取代 mysql ?把 mysql 换成 mariadb 是否更好?我对 mariadb 完全陌生,看来得多学习学习了:)
为什么压力测试时,单 nginx 压力越高,反而表现越好了?
有没有比 debian + nginx + php-fpm + mysql 这个组合更好的方案?似乎问题又回到了原点。。。
debian Apache Nginx Requests8 条回复 • 2016-03-25 23:03:49 +08:00
Andy1999 1
Andy1999 2016-03-25 21:03:55 +08:00 ❤️ 1
Apache 请在 2U4G 的服务器上用
UnisandK 2
UnisandK 2016-03-25 21:10:33 +08:00 ❤️ 1
正规发行版应该都是稳定的
apache 把线程调度器当包调度器在用,所以高并发情况下性能会急剧下降
mariadb 是 mysql 的分支,你可以把它当 mysql 用,装完命令都是 mysql ,没变化的
yangxiu 3
yangxiu 2016-03-25 21:18:52 +08:00
@Andy1999
这边是自己测试,电脑不好虚拟机开不了大内存。正式的服务器是 E3-1230V2 和 4G 内存,而且是独立服务器
yangxiu 4
yangxiu 2016-03-25 21:23:29 +08:00
@UnisandK
测试的结果是 debian 性能好一些,我自己也是一直 debian 的。
就是无法理解为什么那么多人说 centos 比 debian 稳定,没有那么多人说我就会坚持 debian 的。但是既然有人说了,就会忍不住去尝试,去证实。
just1 5
just1 2016-03-25 21:53:17 +08:00 via Android
其实发帖可以选择 markdown ,“`就不会换行了
Remember 6
Remember 2016-03-25 22:05:09 +08:00
不买服务的话, centos 不比 debian 更有优势。
yangxiu 7
yangxiu 2016-03-25 22:33:18 +08:00
@just1
用 markdown 编辑重发了
然后超过字数要分段发,后两个附言忘了选 markdown 了囧
yangxiu 8
yangxiu 2016-03-25 23:03:49 +08:00
@Andy1999
@UnisandK
@just1
@Remember
已经修改好重新发了一份,各位移步到 http://www.v2ex.com/t/266404
谢谢各位回答帮助:)

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速