C#使用phantomjs 进行网页整页截屏
C#使用phantomjs 进行网页整页截屏
- hantomjs 是一个基于js的webkit内核无头浏览器 也就是没有显示界面的浏览器,这样访问网页就省去了浏览器的界面绘制所消耗的系统资源,比较适合用于网络测试等应用 。我只是调用了其中的一个截取网页的小功能,可以完美的解析网页的js和css 而且兼容html5,不过最新的1.5版本不支持flash,所以我采用了1.4的版本,能够得到完整的网页体验。
- 先看看执行的效率(4M电信,:30点测试):
- phantomjs的目录结构
- dll挺多的 都是必须的 codecs里面包含编码信息 qcncodecs4.dll 这个是中文支持 里面还有韩文 日文和台湾繁体中文 这玩意必须有 要不然会出现乱码的。
- imageformats目录里面是qgif4.dll和qjpeg4.dll两个dll 是用于图片转换的 默认png格式。
- rasterize.js 就是官方写好的截屏的js代码
- var page = require('webpage').create(),
- address, output, size;
- if (phantom.args.length < || phantom.args.length > ) {
- console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat]');
- console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
- phantom.exit();
- } else {
- address = phantom.args[];
- output = phantom.args[];
- page.viewportSize = { width: , height: };
- if (phantom.args.length === && phantom.args[].substr(-) === ".pdf") {
- size = phantom.args[].split('*');
- page.paperSize = size.length === ? { width: size[], height: size[], border: '0px' }
- : { format: phantom.args[], orientation: 'portrait', border: '1cm' };
- }
- page.open(address, function (status) {
- if (status !== 'success') {
- console.log('Unable to load the address!');
- } else {
- window.setTimeout(function () {
- page.render(output);
- phantom.exit();
- }, );
- }
- });
- }
- 看这个js的意思貌似可以将pdf文件转换为图片文件,我没有测试。我调用的时候只是传了两个参数。
- 下面的就算调用的核心js代码 直接输出图像文件。
- page.render(output);
- 在C#中调用这玩意的代码是:
- private void GetImage(string url) {
- string links = url.IndexOf("http://") > - ? url : "http://" + url;
- #region 启动进程
- Process p = new Process();
- p.StartInfo.FileName = Environment.CurrentDirectory+"//phantomjs.exe";
- p.StartInfo.WorkingDirectory = Environment.CurrentDirectory+"//pic//";
- p.StartInfo.Arguments = string.Format("--ignore-ssl-errors=yes --load-plugins=yes " + Environment.CurrentDirectory + "//rasterize.js " + links + " "+url+".png");
- p.StartInfo.CreateNoWindow = true;
- p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
- if (!p.Start())
- throw new Exception("无法Headless浏览器.");
- #endregion
- }
- 关键是这里
- p.StartInfo.Arguments = string.Format("--ignore-ssl-errors=yes --load-plugins=yes " + Environment.CurrentDirectory + "//rasterize.js " + links + " "+url+".png");
- --ignore-ssl-errors=yes 忽视加密的ssl连接错误
- --load-plugins=yes 载入插件
- 上面的两参数可以不用 ,加上了是为了体验真实的网页体验效果,比如,不载入插件的话 flash就不会加载的。
- Environment.CurrentDirectory + "//rasterize.js " 这里就是调用写好的js驱动代码,下面带上的参数是作用于这个js的。
- links 访问的网址连接,最好加入http://。
- "+url+".png 输出的图片 默认是png格式 当包含了上面 imageformats里面的dll的话 就可以输出jpg格式和gif格式的图片。
- 所有代码就这样子的,用起来很简单,就像在代码中调用cmd一样的。这样就很容易在不错的机子上进行多线程的批量截图而不影响任何操作,效率方面还很不错!
C#使用GDI+制作背景颜色淡入淡出效果的按钮
- 用过QQ2009的网友都知道QQ主面板的界面非常炫丽,特别好看,鼠标移上去还有淡入淡出的效果。那这样效果是怎么做出来的呢?其实不难,只要自定义一个用户控件的外怪就可以了,用到GDI+技术和时钟控件来操作…
- 首先我们在VS2008里面新建一个Windows窗体控件库的项目,系统会自动生成一个用户控件UserControl1.cs出来,我们就用默认的名字吧~~
- 本例子下载地址:http://files.cnblogs.com/mengxin523/自定义按钮控件.rar
- 程序所有代码如下:
- using System;
- using System.Data;
- using System.Drawing;
- using System.Collections;
- using System.Windows.Forms;
- using System.ComponentModel;
- using System.Drawing.Drawing2D;
- namespace MyButton
- {
- public partial class UserControl1 : UserControl
- {
- private bool calledbykey = false;
- private State mButtonState = State.None; //按钮的状态
- private Timer mFadeIn = new Timer(); //淡入的时钟
- private Timer mFadeOut = new Timer(); //淡出的时钟
- private int mGlowAlpha = ; //透明度
- private System.ComponentModel.Container components = null;
- public UserControl1()
- {
- InitializeComponent();
- //一下几个语句是对控件进行设置和对GDI+进行优化
- this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
- this.SetStyle(ControlStyles.DoubleBuffer, true);
- this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
- this.SetStyle(ControlStyles.ResizeRedraw, true);
- this.SetStyle(ControlStyles.Selectable, true);
- this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
- this.SetStyle(ControlStyles.UserPaint, true);
- this.UpdateStyles();
- this.BackColor = Color.Transparent; //设置控件背景色透明
- mFadeIn.Interval = ; //淡入速度
- mFadeOut.Interval = ; //淡出速度
- }
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (components != null)
- {
- components.Dispose();
- }
- }
- base.Dispose(disposing);
- }
- private void InitializeComponent()
- {
- this.Name = "MySystemButton";
- this.Size = new System.Drawing.Size(, );
- this.Paint += new System.Windows.Forms.PaintEventHandler(this.VistaButton_Paint);
- this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.VistaButton_KeyUp);
- this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.VistaButton_KeyDown);
- this.MouseEnter += new System.EventHandler(this.VistaButton_MouseEnter);
- this.MouseLeave += new System.EventHandler(this.VistaButton_MouseLeave);
- this.MouseUp += new MouseEventHandler(VistaButton_MouseUp);
- this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.VistaButton_MouseDown);
- this.GotFocus += new EventHandler(VistaButton_MouseEnter);
- this.LostFocus += new EventHandler(VistaButton_MouseLeave);
- this.mFadeIn.Tick += new EventHandler(mFadeIn_Tick);
- this.mFadeOut.Tick += new EventHandler(mFadeOut_Tick);
- this.Resize += new EventHandler(VistaButton_Resize);
- }
- enum State { None, Hover, Pressed };
- /// <summary>
- /// 按钮的样式
- /// </summary>
- public enum Style
- {
- /// <summary>
- /// Draw the button as normal
- /// </summary>
- Default,
- /// <summary>
- /// Only draw the background on mouse over.
- /// </summary>
- Flat
- };
- /// <summary>
- /// 用于设置按钮的用处
- /// </summary>
- public enum UseTo
- {
- Min, Close
- };
- UseTo Ut = UseTo.Close; //默认作为关闭按钮
- [Category("UseTo"),
- DefaultValue(UseTo.Close),
- Browsable(true),
- Description("设置按钮的用处")]
- public UseTo UT
- {
- get
- {
- return Ut;
- }
- set
- {
- Ut = value;
- this.Invalidate();
- }
- }
- private string mText;
- /// <summary>
- /// 按钮上显示的文本
- /// </summary>
- [Category("Text"),
- Description("按钮上显示的文本.")]
- public string ButtonText
- {
- get { return mText; }
- set { mText = value; this.Invalidate(); }
- }
- private Color mForeColor = Color.White;
- /// <summary>
- /// 文本颜色
- /// </summary>
- [Category("Text"),
- Browsable(true),
- DefaultValue(typeof(Color), "White"),
- Description("文本颜色.")]
- public override Color ForeColor
- {
- get { return mForeColor; }
- set { mForeColor = value; this.Invalidate(); }
- }
- private ContentAlignment mTextAlign = ContentAlignment.MiddleCenter;
- /// <summary>
- /// 文本对齐方式
- /// </summary>
- [Category("Text"),
- DefaultValue(typeof(ContentAlignment), "MiddleCenter")]
- public ContentAlignment TextAlign
- {
- get { return mTextAlign; }
- set { mTextAlign = value; this.Invalidate(); }
- }
- private Image mImage;
- /// <summary>
- 按钮上的图片
- /// </summary>
- [Category("Image"),
- DefaultValue(null)]
- public Image Image
- {
- get { return mImage; }
- set { mImage = value; this.Invalidate(); }
- }
- private ContentAlignment mImageAlign = ContentAlignment.MiddleLeft;
- /// <summary>
- 按钮对齐方式
- /// </summary>
- [Category("Image"),
- DefaultValue(typeof(ContentAlignment), "MiddleLeft")]
- public ContentAlignment ImageAlign
C#使用API屏蔽系统热键和任务管理器
- 最近做的一个winform类型的项目中需要屏蔽系统热键,在网上搜索了一下,基本上都是调用api来进行hook操作,下面的代码就可以完成功能
- using System;
- using System.IO;
- using System.Reflection;
- using System.Runtime.InteropServices;
- using System.Windows.Forms;
- namespace WAT.PMS
- {
- /// <summary>
- /// Description: Hook Helper类,可以屏蔽一些热键并屏蔽任务管理器
- /// Author: ZhangRongHua
- /// Create DateTime: 2009-6-19 20:21
- /// UpdateHistory:
- /// </summary>
- public class HookHelper
- {
- #region Delegates
- public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
- #endregion
- #region 变量声明
- private HookProc KeyboardHookProcedure;
- private FileStream MyFs; // 用流来屏蔽ctrl alt delete
- private const byte LLKHF_ALTDOWN = 0x20;
- private const byte VK_CAPITAL = 0x14;
- private const byte VK_ESCAPE = 0x1B;
- private const byte VK_F4 = 0x73;
- private const byte VK_LCONTROL = 0xA2;
- private const byte VK_NUMLOCK = 0x90;
- private const byte VK_RCONTROL = 0xA3;
- private const byte VK_SHIFT = 0x10;
- private const byte VK_TAB = 0x09;
- public const int WH_KEYBOARD = ;
- private const int WH_KEYBOARD_LL = ;
- private const int WH_MOUSE = ;
- private const int WH_MOUSE_LL = ;
- private const int WM_KEYDOWN = 0x100;
- private const int WM_KEYUP = 0x101;
- private const int WM_LBUTTONDBLCLK = 0x203;
- private const int WM_LBUTTONDOWN = 0x201;
- private const int WM_LBUTTONUP = 0x202;
- private const int WM_MBUTTONDBLCLK = 0x209;
- private const int WM_MBUTTONDOWN = 0x207;
- private const int WM_MBUTTONUP = 0x208;
- private const int WM_MOUSEMOVE = 0x200;
- private const int WM_MOUSEWHEEL = 0x020A;
- private const int WM_RBUTTONDBLCLK = 0x206;
- private const int WM_RBUTTONDOWN = 0x204;
- private const int WM_RBUTTONUP = 0x205;
- private const int WM_SYSKEYDOWN = 0x104;
- private const int WM_SYSKEYUP = 0x105;
- private static int hKeyboardHook = ;
- #endregion
- #region 函数转换
- [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
- public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
- // 卸载钩子
- [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
- public static extern bool UnhookWindowsHookEx(int idHook);
- // 继续下一个钩子
- [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
- public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
- // 取得当前线程编号
- [DllImport("kernel32.dll")]
- private static extern int GetCurrentThreadId();
- [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
- private static extern short GetKeyState(int vKey);
- #endregion
- #region 方法
- /// <summary>
- /// 钩子回调函数,在这里屏蔽热键。
- /// <remark>
- /// Author:ZhangRongHua
- /// Create DateTime: 2009-6-19 20:19
- /// Update History:
- /// </remark>
- /// </summary>
- /// <param name="nCode">The n code.</param>
- /// <param name="wParam">The w param.</param>
- /// <param name="lParam">The l param.</param>
- /// <returns></returns>
- private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
- {
- KeyMSG m = (KeyMSG) Marshal.PtrToStructure(lParam, typeof (KeyMSG));
- if (((Keys) m.vkCode == Keys.LWin) || ((Keys) m.vkCode == Keys.RWin) ||
- ((m.vkCode == VK_TAB) && ((m.flags & LLKHF_ALTDOWN) != )) ||
- ((m.vkCode == VK_ESCAPE) && ((m.flags & LLKHF_ALTDOWN) != )) ||
- ((m.vkCode == VK_F4) && ((m.flags & LLKHF_ALTDOWN) != )) ||
- (m.vkCode == VK_ESCAPE) && ((GetKeyState(VK_LCONTROL) & 0x8000) != ) ||
- (m.vkCode == VK_ESCAPE) && ((GetKeyState(VK_RCONTROL) & 0x8000) != )
- )
- {
- return ;
- }
- return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
- }
- /// <summary>
- /// 启动Hook,并用流屏蔽任务管理器
- /// <remark>
- /// Author:ZhangRongHua
- /// Create DateTime: 2009-6-19 20:20
- /// Update History:
- /// </remark>
- /// </summary>
- public void HookStart()
- {
- if (hKeyboardHook == )
- {
- // 创建HookProc实例
- KeyboardHookProcedure = new HookProc(KeyboardHookProc);
- hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD,
- KeyboardHookProcedure,
- Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[]),
- );
- // 如果设置钩子失败
- if (hKeyboardHook == )
- {
- HookStop();
- //throw new Exception("SetWindowsHookEx failedeeeeeeee.");
- }
- //用二进制流的方法打开任务管理器。而且不关闭流.这样任务管理器就打开不了
- MyFs = new FileStream(Environment.ExpandEnvironmentVariables("%windir%\\system32\\taskmgr.exe"),
- FileMode.Open);
- byte[] MyByte = new byte[(int) MyFs.Length];
- MyFs.Write(MyByte, , (int) MyFs.Length);
- }
- }
- /// <summary>
- /// 卸载hook,并关闭流,取消屏蔽任务管理器。
- /// <remark>
- /// Author:ZhangRongHua
- /// Create DateTime: 2009-6-19 20:21
- /// Update History:
- /// </remark>
- /// </summary>
- public void HookStop()
- {
- bool retKeyboard = true;
- if (hKeyboardHook != )
- {
- retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
- hKeyboardHook = ;
- }
- if (null != MyFs)
- {
- MyFs.Close();
- }
- if (!(retKeyboard))
- {
- throw new Exception("UnhookWindowsHookEx failedsssss.");
- }
- }
- #endregion
- #region Nested type: KeyMSG
- public struct KeyMSG
- {
- public int dwExtraInfo;
- public int flags;
- public int scanCode;
- public int time;
- public int vkCode;
- }
- #endregion
- }
- }
- PS:也可以通过将[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System] 下的DisableTaskmgr项的值设为"1”来屏蔽任务管理器。
C#操作Win32 API函数
- 摘要:这里介绍C#操作Win32 API函数,C#使用的类库是.Net框架为所有.Net程序开发提供的一个共有的类库——.Net FrameWork SDK。
- C#语言有很多值得学习的地方,这里我们主要介绍C#操作Win32 API函数,包括介绍section:INI文件中的段落名称等方面。
- C#操作Win32 API函数
- C#并不像C++,拥有属于自己的类库。C#使用的类库是.Net框架为所有.Net程序开发提供的一个共有的类库——.Net FrameWork SDK。虽然.Net FrameWork SDK内容十分庞大,功能也非常强大,但还不能面面俱到,至少它并没有提供直接操作INI文件所需要的相关的类。在本文中,C#操作Win32 API函数——WritePrivateProfileString()和GetPrivateProfileString()函数。这二个函数都位于“kernel32.dll”文件中。
- 我们知道在C#中使用的类库都是托管代码(Managed Code)文件,而Win32的API函数所处的文件,都是非托管代码(Unmanaged Code)文件。这就导致了在C#中不可能直接使用这些非托管代码文件中的函数。好在.Net框架为了保持对下的兼容,也为了充分利用以前的资源,提出了互操作,通过互操作可以实现对Win32的API函数的调用。互操作不仅适用于Win32的API函数,还可以用来访问托管的COM对象。C#中对 Win32的API函数的互操作是通过命名空间“System.Runtime.InteropServices”中的“DllImport”特征类来实现的。它的主要作用是指示此属性化方法是作为非托管DLL的输出实现的。下面代码就是在C#利用命名空间 “System.Runtime.InteropServices”中的“DllImport”特征类申明上面二个Win32的API函数:
- C#操作Win32 API函数:
- [ DllImport ( "kernel32" ) ]
- private static extern long WritePrivateProfileString ( string
- section ,
- string key , string val , string filePath ) ;
- 参数说明:section:INI文件中的段落;key:INI文件中的关键字;val:INI文件中关键字的数值;filePath:INI文件的完整的路径和名称。
- C#申明INI文件的读操作函数GetPrivateProfileString():
- [ DllImport ( "kernel32" ) ]
- private static extern int GetPrivateProfileString ( string section ,
- string key , string def , StringBuilder retVal ,
- int size , string filePath ) ;
- 参数说明:section:INI文件中的段落名称;key:INI文件中的关键字;def:无法读取时候时候的缺省数值;retVal:读取数值;size:数值的大小;filePath:INI文件的完整路径和名称。
- 下面是一个读写INI文件的类
- public class INIClass
- {
- public string inipath;
- [DllImport("kernel32")]
- private static extern long WritePrivateProfileString
- (string section,string key,string val,string filePath);
- [DllImport("kernel32")]
- private static extern int GetPrivateProfileString
- (string section,string key,string def,StringBuilder retVal,int size,string filePath);
- ///
- /// 构造方法
- ///
- /// 文件路径
- public INIClass(string INIPath)
- {
- inipath = INIPath;
- }
- ///
- /// 写入INI文件
- ///
- /// 项目名称(如 [TypeName] )
- /// 键
- /// 值
- public void IniWriteValue(string Section,string Key,string Value)
- {
- WritePrivateProfileString(Section,Key,Value,this.inipath);
- }
- ///
- /// 读出INI文件
- ///
- /// 项目名称(如 [TypeName] )
- /// 键
- public string IniReadValue(string Section,string Key)
- {
- StringBuilder temp = new StringBuilder();
- int i = GetPrivateProfileString(Section,Key,"",temp,,this.inipath);
- return temp.ToString();
- }
- ///
- /// 验证文件是否存在
- ///
- /// 布尔值
- public bool ExistINIFile()
- {
- return File.Exists(inipath);
- }
- }
C#使用phantomjs 进行网页整页截屏的更多相关文章
- 用phantomjs 进行网页整页截屏
写截取整个网页程序是一个做前台的哥们所托,要做一些漂亮的界面原形,参考一些不错的网站设计就帮他弄了个截屏的程序. phantomjs 是一个基于js的webkit内核无头浏览器 也就是没有显示界面 ...
- js利用clipboardData在网页中实现截屏粘贴的功能
目前仅有高版本的 Chrome 浏览器支持这样直接粘贴,其他浏览器目前为止还无法粘贴,不过火狐和ie11浏览器在可编辑的div中能够粘贴截图的图片也是base64位和Chrome利用clipboard ...
- 利用 clipboardData 在网页中实现截屏粘贴的功能
<!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...
- 利用Chrome开发者工具功能进行网页整页截图的方法
第一步:打开chrome开发者工具. 打开你想截图的网页,然后按下 F12(macOS 是 option + command + i)调出开发者工具,接着按「Ctrl + Shift + P」(mac ...
- chrome开发者工具实现整站截屏
我们经常要遇到将整个网站作为图片保存下来的情况,而windows系统自带的PrintScreen键只能保存当前屏幕的截图 在chrome浏览器中可以安装第三方的截图插件实现整站截图 今天我们要介绍的方 ...
- chrome实现网页高清截屏(F12、shift+ctrl+p、capture)
打开需要载屏的网页,在键盘上按下F12,出现以下界面 上图圈出的部分有可能会出现在浏览器下方,这并没有关系.此时按下 Ctrl + Shift + P(Mac 为 ⌘Command +⇧Shift + ...
- Snipaste强大离线/在线截屏软件的下载、安装和使用
步骤一: https://zh.snipaste.com/ ,去此官网下载. 步骤二:由于此是个绿色软件,直接解压即可. 步骤三:使用,见官网.ttps://zh.snipaste.com 按F1 ...
- php结合phantomjs实现网页截屏、抓取js渲染的页面
首先PhantomJS快速入门 PhantomJS是一个基于 WebKit 的服务器端 JavaScript API.它全面支持web而不需浏览器支持,其快速,原生支持各种Web标准: DOM 处理, ...
- 利用PhantomJS进行网页截屏,完美解决截取高度的问题
关于PhantomJS PhantomJS 是一个基于WebKit的服务器端 JavaScript API.它全面支持web而不需浏览器支持,其快速,原生支持各种Web标准: DOM 处理, CSS ...
随机推荐
- python2.7+appium第一个脚本(使用夜神模拟器)
搭建好环境后,可以开始准备脚本的编写工作 目录 1.安装夜神模拟器 2.使用uiautomatorviewer定位 3.运行第一个脚本 1.安装夜神模拟器 第一步:官网下载夜神模拟器,完成安装 双击下 ...
- 使用fiddler,提示系统找不到相应的文件FSE2.exe文件
使用fiddler时候遇到了如下问题: Rules中customize rules 时,提示系统找不到相应的文件FSE2.exe文件. 这个文件的位置可以在Tools->opinions-> ...
- 【ABAP系列】SAP ABAP诠释BDC的OK CODE含义
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP诠释BDC的OK ...
- 【洛谷p1314】聪明的质监员
聪明的质监员[题目链接] 有关算法: 二分答案: 但是你只二分答案是不够的,因为你check会炸,所以还要考虑前缀和: 首先假装我们的check已经写好了,main函数: int main() { n ...
- 实现简单的计算器(设计UI)
要点说明: 1.一个textedit控件,其余全部是button控件,button布局方式:栅格布局(Grid layout) 2.对窗体的Title进行修改(默认是工程名) 3.在ui文件中设计的U ...
- vue+element Form键盘回车事件页面刷新解决
问题描述:如下代码所示,使用element-ui 中的el-form组件对table进行条件查询,当查询条件仅有一项时,使用@keyup.enter.native事件绑定回车事件,出现点击回车后,浏览 ...
- c知识点总结2
函数 int func(int x){ //x:形式参数 .... } int main(){ .... int res=func(z); //z:实际参数 } 实参与形参具有不同的存储单元, 实参与 ...
- bootstrap复习
菜单 <div class="row">下拉菜单/分裂菜单</div> <div class="dropdown btn-group&quo ...
- 关于webpack高版本向低版本切换 如何切换?
卸载:npm uninstall webpack -g 重新安装:npm install webpack@3.7.1 -g 直接安装指定版本就行了,如安装 2.4.1 版:cnpm install w ...
- UNIX网络编程总结一
客户与服务器通信使用TCP在同一网络通信时,大致按下面的方式通信:client→TCP→IP→以太网驱动程序→以太网→以太网驱动程序→IP→TCP→server.若不在同一网络则需要路由器连接. 客户 ...